<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[&yet blog]]></title><description><![CDATA[The wonderful blog for &yet.]]></description><link>https://blog.andyet.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 12 May 2021 22:38:47 GMT</lastBuildDate><item><title><![CDATA[Coders are people, too]]></title><description><![CDATA[We talk a lot about people at &yet: putting people first in business; replacing words like “users” or “customers” with “people” whenever…]]></description><link>https://blog.andyet.com/2021/02/16/coders-are-people-too/</link><guid isPermaLink="false">https://blog.andyet.com/2021/02/16/coders-are-people-too/</guid><pubDate>Tue, 16 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We talk a lot about &lt;em&gt;people&lt;/em&gt; at &amp;#x26;yet: putting people first in business; replacing words like “users” or “customers” with “people” whenever possible; the fact that (as &lt;a href=&quot;https://twitter.com/hypirlink/status/620638157177004033&quot;&gt;one of our best-loved t-shirts&lt;/a&gt; reminds us) &lt;em&gt;software is about people.&lt;/em&gt; I recently upgraded my desktop wallpaper to &lt;a href=&quot;https://blog.andyet.com/2018/07/17/upgrade-your-style-with-andyet-desktop-wallpapers/&quot;&gt;this beautiful “Pixels are about people” graphic&lt;/a&gt;, as a kind of talisman I can refer to throughout my day. &lt;/p&gt;
&lt;p&gt;It’s a conscious choice we make, putting &lt;em&gt;people&lt;/em&gt; front and center in our language — because it’s far too easy to lose sight of the wildly complex, multifaceted, fascinating &lt;em&gt;people&lt;/em&gt; we’re making things for. And we believe with our whole hearts that business and whole-humanness are not just compatible, but that it’s possible to build thriving businesses precisely &lt;em&gt;by&lt;/em&gt; putting people first, and making space for humanity and humane-ness. &lt;/p&gt;
&lt;p&gt;(This is also why we’ve been so focused on weirdos lately — because when you take the time to connect with your weirdos, you put that human connection first, and build trust from a place of genuine shared interest.)&lt;/p&gt;
&lt;p&gt;Recently we had the opportunity to work with the folks at Heroku and Salesforce on a project that we’ve fallen in love with. &lt;a href=&quot;https://wickedcoolkit.com/&quot;&gt;Wicked Coolkit&lt;/a&gt; is a collection of retro style, open-source web tools that are built on Heroku &amp;#x26; Salesforce, and that allow web developers to showcase their multi-facetedness.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d34d8e984d2ac75d4c63ac05d5ba1dab/e5166/wicked-coolkit-1.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 27.1523178807947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEE/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAcMIgP/EABgQAAIDAAAAAAAAAAAAAAAAAAASAhEh/9oACAEBAAEFAnH2dH//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAZEAEBAAMBAAAAAAAAAAAAAAABAAIRMlH/2gAIAQEABj8C4ITEjXl//8QAGRABAAIDAAAAAAAAAAAAAAAAEQABITHh/9oACAEBAAE/ITxmsBkIFgKuf//aAAwDAQACAAMAAAAQ+A//xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QADCC/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAh/9oACAECAQE/EFXWb//EABwQAQEAAgIDAAAAAAAAAAAAAAERACFBUWFx0f/aAAgBAQABPxC6WBvQ+YwAnCDfD2ZZaVs5bfWf/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Wicked Coolkit retro logo&quot;
        title=&quot;&quot;
        src=&quot;/static/d34d8e984d2ac75d4c63ac05d5ba1dab/3cb18/wicked-coolkit-1.jpg&quot;
        srcset=&quot;/static/d34d8e984d2ac75d4c63ac05d5ba1dab/0a254/wicked-coolkit-1.jpg 151w,
/static/d34d8e984d2ac75d4c63ac05d5ba1dab/c8fe0/wicked-coolkit-1.jpg 303w,
/static/d34d8e984d2ac75d4c63ac05d5ba1dab/3cb18/wicked-coolkit-1.jpg 605w,
/static/d34d8e984d2ac75d4c63ac05d5ba1dab/39048/wicked-coolkit-1.jpg 908w,
/static/d34d8e984d2ac75d4c63ac05d5ba1dab/e5166/wicked-coolkit-1.jpg 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We know a lot of coders, and none of them are &lt;em&gt;just&lt;/em&gt; coders: they’re coders who also knit, cycle, parent, cook, make art, dance, read, write, engage in civic life, do puzzles, garden, and so on. A lot of us have stories about how our hobbies made us better coders, or opened up new avenues in our work; and many of us apply our coding skills to &lt;a href=&quot;https://lynnandtonic.com/web/&quot;&gt;personal projects&lt;/a&gt; that focus on our interests outside of work. We aren’t &lt;em&gt;just&lt;/em&gt; coders; we’re &lt;em&gt;people&lt;/em&gt; who code.&lt;/p&gt;
&lt;p&gt;Now, Heroku is a platform a lot of devs use for personal projects; it’s nimble and flexible, and lets you spin something up quickly and efficiently, and iterate on it over time. But the folks at Heroku are aware that their parent company, Salesforce, doesn’t have the same associations in most devs’ minds; most of us perceive Salesforce as a big, enterprise CRM, focused on business needs — the opposite of lightweight, and not something you’d consider using on a personal project. &lt;/p&gt;
&lt;p&gt;It turns out, though, that you &lt;em&gt;can&lt;/em&gt; use Salesforce to build something lightweight, personal, and fun — but rather than trying to convince anyone of that, we partnered up with their team to build an example of exactly that, in a way that allows coders to play around and tinker with it. &lt;/p&gt;
&lt;p&gt;We wanted whatever we created to really reflect that “personal project” vibe, while also making use of some of the data management stuff Salesforce excels at. And while we were throwing around ideas, we kept coming back to the nostalgia we’ve been hearing from friends and colleagues about the 1990s-era web — back when the web was smaller, weirder, and way harder to find your way around. (Anyone remember &lt;a href=&quot;https://stackoverflow.com/questions/6252471/what-is-the-use-of-tilde-in-url&quot;&gt;how many URLs had tildes (~) in them&lt;/a&gt;? And how hit-and-miss search engines were before Google?) &lt;/p&gt;
&lt;p&gt;&lt;em&gt;What if,&lt;/em&gt; we wondered, &lt;em&gt;we created a way for web devs to set up a kind of profile that&lt;/em&gt; wasn’t &lt;em&gt;another social network? Just a little personal profile, with a mix of professional and personal interests, that looked cool and could be shared and linked with friends?&lt;/em&gt; We started playing around with the idea of a trading card — like you might collect for your favorite sport, or Magic: The Gathering. And as we iterated on that idea, we came up with a couple of complementary tools to round out the set. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wickedcoolkit.com/&quot;&gt;Wicked Coolkit&lt;/a&gt; launches this week, and we’re kicking it off with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Developer trading card:&lt;/strong&gt; share your feats of strength — both coding-related and otherwise.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 66.88741721854305%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsSAAALEgHS3X78AAACyElEQVQozyWRy1PaUBjF88+66Ey3brqp00UXzrTq9OH4QKZqUYuKgCLPgGLMkxCSm8QEktybBJRHwkMU8VGbtjO/xdmc+c53Dqao8k6sHM9Q8QKbYcQcD7K8nKmAOK9+3i8PEBAclDPg76HB1w0Jmo++4blW21ZBhcVEEWwuE9kDaW9PxAnU9cfnSnflsrUqDeZ2ybEjFSU7yVovQ7h/XKdk0/ecZBa5UJU4GhMFaX2RSOyC05zJKb1QDs1nnHWuN1Py3m5e+kh66DmTLrz1rJGDHjrmtW8Dv9N0dYmlMVkCkRCb/CU/TJ5iRbR2an0/a0qtuzicvIuQHgI2RIAwpgNU8Qa9YWuAdJtRXE2WKgymAsBRiMibxRLcOjHmtpWZ3fo80W5OXpcO6GsI0lIvW2xO+xCvdV3b0ev1aEqVRaDwDCbx4tY2n0iCN7Pp9wt4JEkuRYmlBBUjwOwK3ndkr+/ceOi+b0461tQzJ2M4fmzeNDUxiK0IYjhUisfJRIo5TdN4gS7kafKikqXkD6v5UUcBJY1Lya8jczejxOr2sKFtbdauVFUOLl8J4skBSZwLJZwvlmrpPF+4AASv5yvGpzDuu7IIu0B3nofmeUkT6qbvmBSuu1bQdmCu1lLRyyoFyLJIk4CvapygsVUNZ/WFUL5ry8O+4/lo0jeffPQ8hA8Da9S0O86VyDJYvSYmI+epw3Jyv3x8RJwckxStVAS9zOlfNgqDllyTm1XdnQ5gnO82Wm6vbeeijtvQQBBbZas7X7Op6EVip5yIErHoZfyIzhdrsbT4cTHVRsBtWEhr3PqmdNO66Vita4u3246lChSFXRtK5NvJ3np6J5SJbGR+hrNb4dyPcG55LXtweAaDSlgaVJjgwyuOljkGBIJneJI0VQGbjuDTPXocw4Cnv1gBz2P4PLZe7oKFrLFn/OfWM/8JMxB3vhEY/wDqvXiZVKPqBwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Lynn Fisher‘s developer trading card featuring feats of strength and stickers&quot;
        title=&quot;&quot;
        src=&quot;/static/212473a0c34dd243050344314bb39c96/90cbd/wicked-coolkit-2.png&quot;
        srcset=&quot;/static/212473a0c34dd243050344314bb39c96/29fe9/wicked-coolkit-2.png 151w,
/static/212473a0c34dd243050344314bb39c96/6728c/wicked-coolkit-2.png 303w,
/static/212473a0c34dd243050344314bb39c96/90cbd/wicked-coolkit-2.png 605w,
/static/212473a0c34dd243050344314bb39c96/a2b88/wicked-coolkit-2.png 908w,
/static/212473a0c34dd243050344314bb39c96/c1b63/wicked-coolkit-2.png 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;span class=&quot;footnote&quot;&gt;&lt;a href=&quot;https://lynnandtonic.herokuapp.com/&quot;&gt;See this trading card live.&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Webring:&lt;/strong&gt; build connections between you and your friends, or folks who share your niche interests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/aca5e1d9259c09fbc0044d7560fdddd9/c1b63/wicked-coolkit-4.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 25.165562913907287%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAAsSAAALEgHS3X78AAABFUlEQVQY02P4/uHBx1d33jy99fb57XdgBGK8uANEQMabF0B0B4hev7jzCoxeg9HHN/d+fHjA8PvL41kTliVHtaQldSUmdiWm98Vl9oel9gWn9wflTPYtmOpWOM2haLp1yUz90lm6lXP1qucL5c8qnL7+/+eHQM2PprYsifVsiQnsCA3s9Avs9grucw7tt4uYZBUz1TRhuk7yLOW0OTKZ8/myFzLmLWErXc5QsDyid/3/D/cZ/nx7tHTi1uKo+fV5K0oylqcmLk1OXhGXvjoye21o7nr//E1eRVtcSrdZV+wwqt4tV7tXv+ugQsfhzFn7/n+4y/Dj48P3L+48v3/9+YPrLx7eePmIAHr68MaTBzeAwQH0MwDafsRa5+wN5QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Webring&quot;
        title=&quot;&quot;
        src=&quot;/static/aca5e1d9259c09fbc0044d7560fdddd9/90cbd/wicked-coolkit-4.png&quot;
        srcset=&quot;/static/aca5e1d9259c09fbc0044d7560fdddd9/29fe9/wicked-coolkit-4.png 151w,
/static/aca5e1d9259c09fbc0044d7560fdddd9/6728c/wicked-coolkit-4.png 303w,
/static/aca5e1d9259c09fbc0044d7560fdddd9/90cbd/wicked-coolkit-4.png 605w,
/static/aca5e1d9259c09fbc0044d7560fdddd9/a2b88/wicked-coolkit-4.png 908w,
/static/aca5e1d9259c09fbc0044d7560fdddd9/c1b63/wicked-coolkit-4.png 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hit counter:&lt;/strong&gt; because it wouldn’t be the retro web without a hit counter that shows how many people came to your site (or how many times they hit refresh).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c3cd193ecae6a64c7f3afab434bb00ca/c1b63/wicked-coolkit-3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 25.165562913907287%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAAsSAAALEgHS3X78AAAAs0lEQVQY02P4/uE+Mvrx8cGvzw9+fUJBvz89+PnpAZpKIGJA1Xn/85t7b5/ffvfiztsXd9+8vPP65d2XL++9eHn3zet7+DR/fXfv/8/HR7YdK4hfkpe7JrVoQ1TFVr+6XRYt+2U6jnpM2P/p5S2g/d+wav72/v6vzw+f3rm6f9vBAzsP7991ZM/uo7v3HN2x9/jGvcf3HD4JNB3oNJzO/g7WD7T//4/HUPI7ED0CMx5hOhsAAdUGampoZ9YAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Hit counter&quot;
        title=&quot;&quot;
        src=&quot;/static/c3cd193ecae6a64c7f3afab434bb00ca/90cbd/wicked-coolkit-3.png&quot;
        srcset=&quot;/static/c3cd193ecae6a64c7f3afab434bb00ca/29fe9/wicked-coolkit-3.png 151w,
/static/c3cd193ecae6a64c7f3afab434bb00ca/6728c/wicked-coolkit-3.png 303w,
/static/c3cd193ecae6a64c7f3afab434bb00ca/90cbd/wicked-coolkit-3.png 605w,
/static/c3cd193ecae6a64c7f3afab434bb00ca/a2b88/wicked-coolkit-3.png 908w,
/static/c3cd193ecae6a64c7f3afab434bb00ca/c1b63/wicked-coolkit-3.png 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One of the things that turned out to be really fun (and maybe in retrospect, unsurprising) about this project was that because all of us had permission to infuse our own personal interests into it, everyone involved brought a ton of creative energy, warmth, and devotion to the process. You’ll see little touches everywhere that reflect the level of care that everyone feels, from the 1990s aesthetic to the niche hobbies you can “stick” to your trading card. &lt;/p&gt;
&lt;p&gt;As Julián Duque, one of Heroku’s developer advocates, put it on &lt;a href=&quot;https://www.heroku.com/podcasts/codeish/108-building-community-with-the-wicked-coolkit&quot;&gt;a recent episode of the Code[ish] podcast&lt;/a&gt;: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One thing I love about the project and how we are using it — Heroku and Salesforce, and it happened to me before joining Salesforce — is you see it as this super enterprise software for super serious, square applications, and always the use cases you&apos;ll find are enterprise-y, business-y. And for people maybe like me or the weirdos out there, sometimes those use cases might not be as interested and are doing some other fun projects on the web. But being able to use the power of Salesforce or leveraging Salesforce, how can we use their database capabilities to manage all the data, to be able to feed these type of applications, right? Something as cool as Wicked Coolkit, it shows the power of both platforms, both the Salesforce and Heroku platform, and how can they work together and create really cool use cases.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We’re really proud of this one, and we hope you’ll share it with your favorite people who code. &lt;/p&gt;
&lt;h2 id=&quot;more-about-wicked-coolkit&quot;&gt;&lt;a href=&quot;#more-about-wicked-coolkit&quot; aria-label=&quot;more about wicked coolkit permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More about Wicked Coolkit:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;🎙 Listen: &lt;a href=&quot;https://www.heroku.com/podcasts/codeish/108-building-community-with-the-wicked-coolkit&quot;&gt;&amp;#x26;yet’s Chief Creative Officer, Lynn Fisher, in conversation with Heroku’s developer advocates on the Code[ish] podcast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;📝 Read: &lt;a href=&quot;https://find.yourweirdos.com/posts/show-dont-tell&quot;&gt;how this project aligns with our “Find Your Weirdos” approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;⚡ Play: &lt;a href=&quot;https://wickedcoolkit.com/&quot;&gt;wickedcoolkit.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;💻 Contribute: &lt;a href=&quot;https://github.com/fostive/wicked-coolkit-user&quot;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Recommended resources]]></title><description><![CDATA[These book links are affiliate links that point to Bookshop.org. If you use these links to buy something, we may earn a commission. We…]]></description><link>https://blog.andyet.com/2020/07/09/recommended-resources/</link><guid isPermaLink="false">https://blog.andyet.com/2020/07/09/recommended-resources/</guid><pubDate>Thu, 09 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This post is part of a series originally shared on &lt;a href=&quot;https://togetherness.is&quot;&gt;togetherness.is&lt;/a&gt;, a people-first resource for gathering remotely.&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/25/togetherness/&apos;&gt;Togetherness&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/26/sit-in-the-bad-seats/&apos;&gt;Sit in the bad seats&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/06/29/have-your-passports-ready/&apos;&gt;Have your passports ready&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/07/02/give-your-attendees-the-wheel/&apos;&gt;Give your attendees the wheel&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Recommended resources&lt;/strong&gt; (You are here)&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Curated inspiration, short reads, books, podcasts, and tools.&lt;/p&gt;
&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 18.543046357615893%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAAsSAAALEgHS3X78AAAArklEQVQI122OvQvCMBDF+/c7ObkIUr9BcOlgQcRFXdJq2jSh1NriUHCyiCBam7uYuIl9093v3j2eJQEUAH4FAGZFlAYA1rWeFRqogfqTtQ7FkorRhjg+mxC2IDQ4Zi4V871wDnwXp1OPr2h0LUvtxt8Ia8zzNkla29A9Fd3o3PHioS/sIB2wfJYUfZbZNOmF2eV2b3iuEJ+6ICqJWAM+JL4kVIBvA81JF9Ye2VT7A35M3IMl22NiAAAAAElFTkSuQmCC&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;Inspiration&quot; title src=&quot;/static/b605bc7a57e1ae782ba04f9a8fad0b34/90cbd/resources-inspiration.png&quot; srcset=&quot;/static/b605bc7a57e1ae782ba04f9a8fad0b34/29fe9/resources-inspiration.png 151w,
/static/b605bc7a57e1ae782ba04f9a8fad0b34/6728c/resources-inspiration.png 303w,
/static/b605bc7a57e1ae782ba04f9a8fad0b34/90cbd/resources-inspiration.png 605w,
/static/b605bc7a57e1ae782ba04f9a8fad0b34/a2b88/resources-inspiration.png 908w,
/static/b605bc7a57e1ae782ba04f9a8fad0b34/c1b63/resources-inspiration.png 1200w&quot; sizes=&quot;(max-width: 605px) 100vw, 605px&quot;&gt;
  &lt;/span&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://www.vogue.com/slideshow/elaine-welteroth-jonathan-singletary-brooklyn-stoop-wedding&quot;&gt;
     &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 56.29139072847682%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAGT00hwhif/xAAaEAADAQADAAAAAAAAAAAAAAACAxIBBCEi/9oACAEBAAEFAlromcchGLzNkFekh2P/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEv/aAAgBAwEBPwFT/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHBABAAEEAwAAAAAAAAAAAAAAAQACAxEhEjFB/9oACAEBAAY/Ammlw4m3yciXE7Egu1Juf//EABoQAQACAwEAAAAAAAAAAAAAAAEAESExYVH/2gAIAQEAAT8hcERZWKkHfBpggBbPYzOgCdjBYC7rk//aAAwDAQACAAMAAAAQd9//xAAXEQEBAQEAAAAAAAAAAAAAAAABABFh/9oACAEDAQE/EBw2OL//xAAVEQEBAAAAAAAAAAAAAAAAAAARAP/aAAgBAgEBPxAYv//EAB0QAQEAAwACAwAAAAAAAAAAAAERACFBMXGBkbH/2gAIAQEAAT8QZw42RIc5WfOQO03YO2b9bwtASoNvcSs2Tgy/h9YlLQ8i3BdrRpiV4Z//2Q==&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;a couple in wedding garb sit on a stoop decorated with tons of flowers&quot; title src=&quot;/static/b5d7572912809f861852dad20a28bca3/066f9/vogue-dancing-in-the-street.jpg&quot; srcset=&quot;/static/b5d7572912809f861852dad20a28bca3/0a254/vogue-dancing-in-the-street.jpg 151w,
/static/b5d7572912809f861852dad20a28bca3/c8fe0/vogue-dancing-in-the-street.jpg 303w,
/static/b5d7572912809f861852dad20a28bca3/066f9/vogue-dancing-in-the-street.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
     &lt;figcaption&gt;Photo: Annabel of Belathee&lt;/figcaption&gt;
  &lt;/a&gt;
  &lt;p&gt;&lt;a href=&quot;https://www.vogue.com/slideshow/elaine-welteroth-jonathan-singletary-brooklyn-stoop-wedding&quot;&gt;Dancing in the Street: Elaine Welteroth Got Married on Her Brooklyn Stoop, Then Threw a Virtual Block Party&lt;/a&gt;, by Alexandra Macon for &lt;em&gt;Vogue&lt;/em&gt;&lt;/p&gt;
  &lt;blockquote&gt;We kicked off our Zoom ceremony with a little &amp;#x201C;love letter&amp;#x201D; exercise and virtual family photo. In our invitation, we asked our guests the following: &amp;#x201C;Write us a love letter: In lieu of a formal guest book and registry, we invite our guests to sow seeds of support via a handwritten letter&amp;#x2014;marriage advice is welcome!&amp;#x2014;that can be mailed to us following the ceremony&amp;#x2014;address is in your invite email. \*Very Important\* On the back of the envelope in large letters, please write one word to take with us on our marriage journey. Note: During the zoom ceremony, guests will be directed to hold up your word for a virtual family photo.&amp;#x201D;&lt;/blockquote&gt;
&lt;/article&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://variety.com/2020/music/news/erykah-badu-quarantine-concert-livestreams-business-1234582892/&quot;&gt;
     &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 56.29139072847682%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAMBAgQF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQP/2gAMAwEAAhADEAAAAeZbM+dFEif/xAAbEAACAwADAAAAAAAAAAAAAAABAgADIREiMf/aAAgBAQABBQJcZgIBzPJVr2Dv/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8Bqv/EABYRAAMAAAAAAAAAAAAAAAAAABARQf/aAAgBAgEBPwFUf//EABsQAAIBBQAAAAAAAAAAAAAAAAABEAIRUWGh/9oACAEBAAY/AsdK9Qh3j//EABsQAAMAAgMAAAAAAAAAAAAAAAABESExQVGx/9oACAEBAAE/IYVIkuxZKxrGQbZyLDO0W2ilCUwvD//aAAwDAQACAAMAAAAQB+//xAAYEQACAwAAAAAAAAAAAAAAAAAAASExQf/aAAgBAwEBPxBPRDD/xAAXEQEBAQEAAAAAAAAAAAAAAAARAAEh/9oACAECAQE/ENEHrf/EABwQAQEAAgIDAAAAAAAAAAAAAAERACFBYYGRwf/aAAgBAQABPxBJaIoF476xQCRUjRQ595PWBohcFC9jswkXVyLq40ACQE4P3P/Z&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;Erykah Badu performing in a very large coat&quot; title src=&quot;/static/f8bb686a29dbd625fe3fb392bdad66a7/066f9/variety-erykah-badu.jpg&quot; srcset=&quot;/static/f8bb686a29dbd625fe3fb392bdad66a7/0a254/variety-erykah-badu.jpg 151w,
/static/f8bb686a29dbd625fe3fb392bdad66a7/c8fe0/variety-erykah-badu.jpg 303w,
/static/f8bb686a29dbd625fe3fb392bdad66a7/066f9/variety-erykah-badu.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
     &lt;figcaption&gt;Photo: Variety&lt;/figcaption&gt;
  &lt;/a&gt;
  &lt;p&gt;&lt;a href=&quot;https://variety.com/2020/music/news/erykah-badu-quarantine-concert-livestreams-business-1234582892/&quot;&gt;How Erykah Badu Created Her Own Livestream Company for &amp;#x2018;Quarantine Concert Series&lt;/a&gt;, by Jem Aswad at &lt;em&gt;Variety&lt;/em&gt;&lt;/p&gt;
  &lt;blockquote&gt;I had to quickly think of something, and like every other artist in the industry, we thought of livestreaming. But I couldn&amp;#x2019;t just put a phone up on a tripod and do a livestream on one of the social platforms, because that would just feed me: I had to figure out a way to keep morale up for all [my] musicians and techs and engineers and keep all of us employed. &lt;br&gt;&lt;br&gt;I wanted to create a livestreamed interactive experience that had the same integrity, ingenuity, creativity and technical aspects of my live shows, because I had to charge something&lt;/blockquote&gt;
&lt;/article&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://blog.andyet.com/2019/01/11/bts-a-remote-holiday-party/&quot;&gt;
     &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 50.9933774834437%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAIBBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHuTZMUX//EABkQAAEFAAAAAAAAAAAAAAAAAAIAARAhQv/aAAgBAQABBQLTIbGf/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAAAIgIVH/2gAIAQEABj8CGs2H/8QAGxABAAMBAAMAAAAAAAAAAAAAAQARMSFRYZH/2gAIAQEAAT8hHoszI3Re/I6Gz2JRtd8ygwC9hk//2gAMAwEAAgADAAAAEPwP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAQEAAwEBAAAAAAAAAAAAAREAIVFhMXH/2gAIAQEAAT8Q+hoHuYgjxTz7uW8/i4JSLIxymL+QWCV9wAAQ6N//2Q==&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;a video call with different yeti faces&quot; title src=&quot;/static/120be61ab81ed1dcca63454501c4c986/3cb18/bts-holiday-call.jpg&quot; srcset=&quot;/static/120be61ab81ed1dcca63454501c4c986/0a254/bts-holiday-call.jpg 151w,
/static/120be61ab81ed1dcca63454501c4c986/c8fe0/bts-holiday-call.jpg 303w,
/static/120be61ab81ed1dcca63454501c4c986/3cb18/bts-holiday-call.jpg 605w,
/static/120be61ab81ed1dcca63454501c4c986/8e1fc/bts-holiday-call.jpg 900w&quot; sizes=&quot;(max-width: 605px) 100vw, 605px&quot;&gt;
  &lt;/span&gt;
  &lt;/a&gt;
  &lt;p&gt;&lt;a href=&quot;https://blog.andyet.com/2019/01/11/bts-a-remote-holiday-party/&quot;&gt;Behind the Scenes: a remote holiday party&lt;/a&gt;, from the &amp;amp;yet blog&lt;/p&gt;
  &lt;blockquote&gt;We love gathering together, but sometimes it&amp;#x2019;s just not an option. So this past December we decided to try an all-remote holiday party. Some activities worked really well and others not as much. Here&amp;#x2019;s a rundown of what we did!&lt;/blockquote&gt;
&lt;/article&gt;
&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 18.543046357615893%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAAsSAAALEgHS3X78AAAAsElEQVQI112PPQuCUBSG/fWNTUGT4NCYEGESNITUYteuR0vFr76GoK0hMvSec/NKQ/XwDs87vByORoQCEQmJ6CNCtEUFUZJCiVQqf9GmDJw4X/Bwti+sjT92AS7XdXGeMLC9YBnGPD/Yu8xisAqi/7HhJXpQDrepGR91nhp+Xt4f89Ot7yY9h+ssMqAYQTZwIzPM1P3vcUOyRqqQGqIXUt090PoTu9qKwEpQI6WQ/7wBEnjbIyMWEp8AAAAASUVORK5CYII=&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;Short Reads&quot; title src=&quot;/static/c2101b9e96086acce63ba309f05c2ec8/90cbd/resources-short-reads.png&quot; srcset=&quot;/static/c2101b9e96086acce63ba309f05c2ec8/29fe9/resources-short-reads.png 151w,
/static/c2101b9e96086acce63ba309f05c2ec8/6728c/resources-short-reads.png 303w,
/static/c2101b9e96086acce63ba309f05c2ec8/90cbd/resources-short-reads.png 605w,
/static/c2101b9e96086acce63ba309f05c2ec8/a2b88/resources-short-reads.png 908w,
/static/c2101b9e96086acce63ba309f05c2ec8/c1b63/resources-short-reads.png 1200w&quot; sizes=&quot;(max-width: 605px) 100vw, 605px&quot;&gt;
  &lt;/span&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://sidedooraccess.com/blog/2020/5/19/7-lessons-learned-after-moderating-dozens-of-live-performances-online&quot;&gt;
     &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 57.6158940397351%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAMC/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAYEpdpj/xAAZEAADAAMAAAAAAAAAAAAAAAAAARESIkL/2gAIAQEAAQUCqRqOmKOmf//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABcQAQADAAAAAAAAAAAAAAAAABAAIXH/2gAIAQEABj8ClGP/xAAbEAADAAMBAQAAAAAAAAAAAAAAAREhMUGhYf/aAAgBAQABPyFtK2fB7JvMiNoo3VeLwfofJ//aAAwDAQACAAMAAAAQS+//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAdEAACAgIDAQAAAAAAAAAAAAABEQAxIUFRYXGB/9oACAEBAAE/EAQLCtM89qCJYFEDLw8fYSFQAqUNsglz0qY8ijLLuoVPJ//Z&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;lots of video calls of musicians&quot; title src=&quot;/static/b74ecd84a5cbacb0be788b6d44f95b5b/066f9/sidedoor-online-shows.jpg&quot; srcset=&quot;/static/b74ecd84a5cbacb0be788b6d44f95b5b/0a254/sidedoor-online-shows.jpg 151w,
/static/b74ecd84a5cbacb0be788b6d44f95b5b/c8fe0/sidedoor-online-shows.jpg 303w,
/static/b74ecd84a5cbacb0be788b6d44f95b5b/066f9/sidedoor-online-shows.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
     &lt;figcaption&gt;Image: Mark Busse&lt;/figcaption&gt;
  &lt;/a&gt;
  &lt;p&gt;&lt;a href=&quot;https://sidedooraccess.com/blog/2020/5/19/7-lessons-learned-after-moderating-dozens-of-live-performances-online&quot;&gt;7 Lessons learned after moderating dozens of online shows&lt;/a&gt;, by Mark Busse at Side Door&lt;/p&gt;
  &lt;blockquote&gt;We&amp;#x2019;ve definitely learned that we miss being together, but an online performance becomes not a replacement, but a whole new connective experience when produced well.&lt;/blockquote&gt;
&lt;/article&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://cv-harquail.squarespace.com/blog/2020/5/14/mini-book-bringing-feminist-practices-into-online-work-sessions&quot;&gt;
     &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 50.331125827814574%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHZVsRjD//EABcQAAMBAAAAAAAAAAAAAAAAAAABESD/2gAIAQEAAQUCKxY//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFhAAAwAAAAAAAAAAAAAAAAAAACBB/9oACAEBAAY/Air/AP/EABsQAAICAwEAAAAAAAAAAAAAAAERACEQUXGh/9oACAEBAAE/IUQGzLdOCMrPkOf/2gAMAwEAAgADAAAAEBDP/8QAFREBAQAAAAAAAAAAAAAAAAAAERD/2gAIAQMBAT8QSf/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAQACAgMBAAAAAAAAAAAAAAEAESFREGGRof/aAAgBAQABPxBrgOgFfYWLcHdcsKiuwPyZEo0cf//Z&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;slide of the title&quot; title src=&quot;/static/03f66b01e95759fb8a7a9aac6dfb966f/066f9/harquail-feminist-practices.jpg&quot; srcset=&quot;/static/03f66b01e95759fb8a7a9aac6dfb966f/0a254/harquail-feminist-practices.jpg 151w,
/static/03f66b01e95759fb8a7a9aac6dfb966f/c8fe0/harquail-feminist-practices.jpg 303w,
/static/03f66b01e95759fb8a7a9aac6dfb966f/066f9/harquail-feminist-practices.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
     &lt;figcaption&gt;Image: CV Harquail&lt;/figcaption&gt;
  &lt;/a&gt;
  &lt;p&gt;&lt;a href=&quot;https://cv-harquail.squarespace.com/blog/2020/5/14/mini-book-bringing-feminist-practices-into-online-work-sessions&quot;&gt;Bringing Feminist Practices into Online Work Sessions&lt;/a&gt;, by CV Harquail at &lt;em&gt;Feminists at Work&lt;/em&gt;&lt;/p&gt;
  &lt;blockquote&gt;The quality of our interactions with each other and the quality of our collective presence determines the kinds of results we get in our work as well as the overall experience we have together. If we prioritizing &amp;#x201C;doing&amp;#x201D; and the accomplishment of tasks, we often diminish or ignore what it takes to &amp;#x201C;be&amp;#x201D; ourselves and to &amp;#x201C;be&amp;#x201D; together.&lt;br&gt;&lt;br&gt;(Here&amp;#x2019;s a &lt;a href=&quot;https://cv-harquail.squarespace.com/blog/2020/4/28/bringing-feminist-practices-into-your-online-meetings&quot;&gt;shorter, two-page summary of the above booklet&lt;/a&gt;.)&lt;/blockquote&gt;
&lt;/article&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://qz.com/1856688/covid-19-is-forcing-the-world-to-reimagine-teleconferencing/&quot;&gt;
     &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 56.29139072847682%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBP/EABYBAQEBAAAAAAAAAAAAAAAAAAADBP/aAAwDAQACEAMQAAAB7LUdUbH/xAAXEAADAQAAAAAAAAAAAAAAAAABEBEg/9oACAEBAAEFAkJj/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGRAAAgMBAAAAAAAAAAAAAAAAADEBESAh/9oACAEBAAY/AuzYxY//xAAcEAACAgIDAAAAAAAAAAAAAAABEQAhMVEQkaH/2gAIAQEAAT8hpbGBOg1KKL2AAYAiDavj/9oADAMBAAIAAwAAABA8L//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/EKf/xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAHRABAAICAgMAAAAAAAAAAAAAAREhAIExQVFhkf/aAAgBAQABPxB4Eoo71eESQo6jcbvDHR8pbEUAejHgiu0lzb9z/9k=&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;many people on video calls&quot; title src=&quot;/static/27a5d6ebdd4b3c563207d605d2fc908c/066f9/conferences_tldr.jpg&quot; srcset=&quot;/static/27a5d6ebdd4b3c563207d605d2fc908c/0a254/conferences_tldr.jpg 151w,
/static/27a5d6ebdd4b3c563207d605d2fc908c/c8fe0/conferences_tldr.jpg 303w,
/static/27a5d6ebdd4b3c563207d605d2fc908c/066f9/conferences_tldr.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
     &lt;figcaption&gt;Image: Maya Ish-Shalom&lt;/figcaption&gt;
  &lt;/a&gt;
  &lt;p&gt;&lt;a href=&quot;https://qz.com/1856688/covid-19-is-forcing-the-world-to-reimagine-teleconferencing/&quot;&gt;Covid-19 is forcing the world to reimagine virtual conferences&lt;/a&gt;, by Anne Quito, Chika Dunga, and Amrita Khalid at &lt;em&gt;Quartz&lt;/em&gt; (paywall)&lt;/p&gt;
  &lt;blockquote&gt;Largely stale formats until now, virtual conferences are being reimagined as a kind of experimental theater for exchange and networking amid this global health crisis.&lt;/blockquote&gt;
&lt;/article&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://www.theatlantic.com/culture/archive/2020/05/dave-grohl-irreplaceable-thrill-rock-show/611113/&quot;&gt;
     &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 60.9271523178808%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwT/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQP/2gAMAwEAAhADEAAAAVXPadJAi//EABoQAAIDAQEAAAAAAAAAAAAAAAACARESIQP/2gAIAQEAAQUC0S9G6Iazz6qdX//EABcRAQADAAAAAAAAAAAAAAAAAAABERL/2gAIAQMBAT8BpmH/xAAWEQADAAAAAAAAAAAAAAAAAAAAARL/2gAIAQIBAT8BplM//8QAGxAAAgEFAAAAAAAAAAAAAAAAAAIhARAxUaH/2gAIAQEABj8CtK9JGroyf//EABoQAQEBAQEBAQAAAAAAAAAAAAERACExYYH/2gAIAQEAAT8hgFfMFWHeXUpZ+RkYQ8woewH7k2Vv/9oADAMBAAIAAwAAABBvH//EABURAQEAAAAAAAAAAAAAAAAAAAEA/9oACAEDAQE/EAwxf//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPxCi7P/EABwQAQEAAgIDAAAAAAAAAAAAAAERACExQWFxsf/aAAgBAQABPxBJSCXFGiIg10Q17xe2LSAmToJgmt4AC0D1yfhhS2rw+c//2Q==&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;Dave Grohl performing in front of a huge crowd&quot; title src=&quot;/static/f39206adf7c8fcf1459f3eab46d4dbe1/066f9/dave-grohl.jpg&quot; srcset=&quot;/static/f39206adf7c8fcf1459f3eab46d4dbe1/0a254/dave-grohl.jpg 151w,
/static/f39206adf7c8fcf1459f3eab46d4dbe1/c8fe0/dave-grohl.jpg 303w,
/static/f39206adf7c8fcf1459f3eab46d4dbe1/066f9/dave-grohl.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
     &lt;figcaption&gt;Image: Thomas Rabsch&lt;/figcaption&gt;
  &lt;/a&gt;
  &lt;p&gt;&lt;a href=&quot;https://www.theatlantic.com/culture/archive/2020/05/dave-grohl-irreplaceable-thrill-rock-show/611113/&quot;&gt;The Day the Live Concert Returns&lt;/a&gt;, by Dave Grohl at &lt;em&gt;The Atlantic&lt;/em&gt;&lt;/p&gt;
  &lt;blockquote&gt;In today&amp;#x2019;s world of fear and unease and social distancing, it&amp;apos;s hard to imagine sharing experiences like these ever again. I don&amp;#x2019;t know when it will be safe to return to singing arm in arm at the top of our lungs, hearts racing, bodies moving, souls bursting with life. But I do know that we will do it again, because we have to. It&amp;#x2019;s not a choice. We&amp;#x2019;re human. We need moments that reassure us that we are not alone. That we are understood. That we are imperfect. And, most important, that we need each other.&lt;/blockquote&gt;
&lt;/article&gt;
&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 18.543046357615893%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAAsSAAALEgHS3X78AAAAaklEQVQI143NuwmAQBAE0Os/sATBRBMLEBQDEYw8fyt+4LAKg5PdWbWDe+EMwxgAqiL4iQgz658EMe1IxXI061HSWQ9U9XM1LAoJGid2T2eXrVdOLp5c1FFmt68IeTcP4AUe6oEHejNYQ73m6OW4c9F4KwAAAABJRU5ErkJggg==&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;Books&quot; title src=&quot;/static/b5b2313445915654f8ac416b8b0bf88e/90cbd/resources-books.png&quot; srcset=&quot;/static/b5b2313445915654f8ac416b8b0bf88e/29fe9/resources-books.png 151w,
/static/b5b2313445915654f8ac416b8b0bf88e/6728c/resources-books.png 303w,
/static/b5b2313445915654f8ac416b8b0bf88e/90cbd/resources-books.png 605w,
/static/b5b2313445915654f8ac416b8b0bf88e/a2b88/resources-books.png 908w,
/static/b5b2313445915654f8ac416b8b0bf88e/c1b63/resources-books.png 1200w&quot; sizes=&quot;(max-width: 605px) 100vw, 605px&quot;&gt;
  &lt;/span&gt;
&lt;p&gt;&lt;small&gt;These book links are affiliate links that point to &lt;a href=&quot;https://bookshop.org/&quot;&gt;Bookshop.org&lt;/a&gt;. If you use these links to buy something, we may earn a commission. We encourage you to buy from your local, independent bookstore, but if you choose to buy through Bookshop, they give away 75% of their profits to independent booksellers, publications, and authors.&lt;/small&gt;&lt;/p&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://bookshop.org/a/10677/9781594634925&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 72.84768211920529%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHtRtMrSGf/xAAYEAEBAAMAAAAAAAAAAAAAAAACAQADEv/aAAgBAQABBQLauAU482ToCKrP/8QAFhEBAQEAAAAAAAAAAAAAAAAAEQEQ/9oACAEDAQE/AYGf/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQIBAT8BZ//EABkQAAIDAQAAAAAAAAAAAAAAAAERAAIQIf/aAAgBAQAGPwJwC3QcQjsEuZ//xAAcEAEAAQQDAAAAAAAAAAAAAAABEQAQIWExQVH/2gAIAQEAAT8hlMpcEVA8HnyzoAu6Z9JEzO7f/9oADAMBAAIAAwAAABBnz//EABgRAAIDAAAAAAAAAAAAAAAAAAEhEEHh/9oACAEDAQE/EAZbyP/EABYRAQEBAAAAAAAAAAAAAAAAAAEQMf/aAAgBAgEBPxBOE//EABsQAQACAgMAAAAAAAAAAAAAAAERMQAQIUHB/9oACAEBAAE/EBsARJ5axqOwLBWl+VIK3gXTIUHhr//Z&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;book cover&quot; title src=&quot;/static/e34ff6a332bdd5d6459803028adbb2ba/066f9/art-of-gathering.jpg&quot; srcset=&quot;/static/e34ff6a332bdd5d6459803028adbb2ba/0a254/art-of-gathering.jpg 151w,
/static/e34ff6a332bdd5d6459803028adbb2ba/c8fe0/art-of-gathering.jpg 303w,
/static/e34ff6a332bdd5d6459803028adbb2ba/066f9/art-of-gathering.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
  &lt;/a&gt;
  &lt;p&gt;Parker, Priya. &lt;em&gt;The Art of Gathering: How We Meet and Why It Matters&lt;/em&gt;&lt;br&gt;&lt;a href=&quot;https://bookshop.org/a/10677/9781594634925&quot;&gt;hard copy&lt;/a&gt; | &lt;a href=&quot;https://www.amazon.com/Art-Gathering-How-Meet-Matters-ebook/dp/B07637KVXL/ref=tmm_kin_swatch_0?_encoding=UTF8&amp;amp;qid=&amp;amp;sr=&quot;&gt;Kindle&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://bookshop.org/a/10677/9781523095568&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 72.84768211920529%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAUEBv/EABUBAQEAAAAAAAAAAAAAAAAAAAID/9oADAMBAAIQAxAAAAHfNpTRbog4/wD/xAAYEAADAQEAAAAAAAAAAAAAAAABAgMEAP/aAAgBAQABBQLaSss1HN+2qWlmm40d/8QAFxEAAwEAAAAAAAAAAAAAAAAAAhAREv/aAAgBAwEBPwEZhf/EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAgEBPwE1f//EAB0QAQABAwUAAAAAAAAAAAAAAAECABAREiFBUZH/2gAIAQEABj8CNKm/FRzOXtjHdRUt/8QAGhABAQADAQEAAAAAAAAAAAAAAREAECFBUf/aAAgBAQABPyFaVnqmE6BXjXmio1nJKQvp81//2gAMAwEAAgADAAAAEAfP/8QAFxEAAwEAAAAAAAAAAAAAAAAAEBEhYf/aAAgBAwEBPxCx6P/EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAECAQE/EKH/xAAbEAEBAAMAAwAAAAAAAAAAAAABEQAQUSFBYf/aAAgBAQABPxBxAJQpHmUOcPD5ag3GlD09yopU/Rx1/9k=&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;book cover&quot; title src=&quot;/static/2090ea91ad7cfc4daaddf7b894e4e685/066f9/community.jpg&quot; srcset=&quot;/static/2090ea91ad7cfc4daaddf7b894e4e685/0a254/community.jpg 151w,
/static/2090ea91ad7cfc4daaddf7b894e4e685/c8fe0/community.jpg 303w,
/static/2090ea91ad7cfc4daaddf7b894e4e685/066f9/community.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
  &lt;/a&gt;
  &lt;p&gt;Block, Peter. &lt;em&gt;Community: The Structure of Belonging&lt;/em&gt;&lt;br&gt;&lt;a href=&quot;https://bookshop.org/a/10677/9781523095568&quot;&gt;hard copy&lt;/a&gt; | &lt;a href=&quot;https://www.amazon.com/Community-Structure-Belonging-Peter-Block-ebook/dp/B07B4P5Z5B/&quot;&gt;Kindle&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://bookshop.org/a/10677/9780865479456&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 72.84768211920529%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAAB1p6ZitEI/wD/xAAaEAACAgMAAAAAAAAAAAAAAAABAgADBBES/9oACAEBAAEFAsg6SosXly9JUpDz/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGRAAAgMBAAAAAAAAAAAAAAAAASEAEFGB/9oACAEBAAY/AlsDNdgVf//EABkQAQEAAwEAAAAAAAAAAAAAAAERABAhMf/aAAgBAQABPyFTUnHmUKXeXUoxaIK6/9oADAMBAAIAAwAAABBzz//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/EBAn/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAR/9oACAECAQE/EHVn/8QAGxABAQACAwEAAAAAAAAAAAAAAREAECExQVH/2gAIAQEAAT8QXZQqj7ju4oUkeNKCWB7mL40Fv01//9k=&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;book cover&quot; title src=&quot;/static/9ead880d27c3e905328f746a140c9dc6/066f9/the-chairs-are-where.jpg&quot; srcset=&quot;/static/9ead880d27c3e905328f746a140c9dc6/0a254/the-chairs-are-where.jpg 151w,
/static/9ead880d27c3e905328f746a140c9dc6/c8fe0/the-chairs-are-where.jpg 303w,
/static/9ead880d27c3e905328f746a140c9dc6/066f9/the-chairs-are-where.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
  &lt;/a&gt;
  &lt;p&gt;Glouberman, Misha and Heti, Sheila. &lt;em&gt;The Chairs Are Where the People Go: How to Live, Work, and Play in the City&lt;/em&gt;&lt;br&gt;&lt;a href=&quot;https://bookshop.org/a/10677/9780865479456&quot;&gt;hard copy&lt;/a&gt; | &lt;a href=&quot;https://www.amazon.com/Chairs-Are-Where-People-Go-ebook/dp/B004GHN2MG/&quot;&gt;Kindle&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://bookshop.org/a/10677/9781734379747&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 72.84768211920529%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABAAF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAwT/2gAMAwEAAhADEAAAAdk6Tzo2qg//xAAZEAACAwEAAAAAAAAAAAAAAAACAwABETL/2gAIAQEAAQUCbeCo7I4zlY4c/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAy/9oACAEDAQE/ARK//8QAFhEAAwAAAAAAAAAAAAAAAAAAAhAy/9oACAECAQE/AStf/8QAFhAAAwAAAAAAAAAAAAAAAAAAACBh/9oACAEBAAY/AiL/AP/EABsQAAIDAAMAAAAAAAAAAAAAAAERABAxIUGR/9oACAEBAAE/ITPD3qAjPqnwHzDuSBr/2gAMAwEAAgADAAAAECfP/8QAFREBAQAAAAAAAAAAAAAAAAAAERD/2gAIAQMBAT8QKn//xAAWEQEBAQAAAAAAAAAAAAAAAAAREIH/2gAIAQIBAT8QZyf/xAAcEAEAAQQDAAAAAAAAAAAAAAABIQAQETFBYYH/2gAIAQEAAT8QEzsO1eFBS6sEJHDNATMKRvFv/9k=&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;book cover&quot; title src=&quot;/static/e8ab3f94355353b1296504d4b32d5504/066f9/connected-from-afar.jpg&quot; srcset=&quot;/static/e8ab3f94355353b1296504d4b32d5504/0a254/connected-from-afar.jpg 151w,
/static/e8ab3f94355353b1296504d4b32d5504/c8fe0/connected-from-afar.jpg 303w,
/static/e8ab3f94355353b1296504d4b32d5504/066f9/connected-from-afar.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
  &lt;/a&gt;
  &lt;p&gt;Vellos, Kat. &lt;em&gt;Connected From Afar: A Guide for Staying Close When You&amp;apos;re Far Away&lt;/em&gt;&lt;br&gt;&lt;a href=&quot;https://bookshop.org/a/10677/9781734379747&quot;&gt;hard copy&lt;/a&gt; | &lt;a href=&quot;https://www.amazon.com/Connected-Afar-Guide-Staying-Close-ebook/dp/B086QBY74W/&quot;&gt;Kindle&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 18.543046357615893%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAAsSAAALEgHS3X78AAAAiklEQVQI13VOsQ6CQAzl//0JZTAOQhjUxcFBBgzKnYhHaISgi19gondpz5b9Xl/b1zYvaeQF5Ik4kYO7lwkReSEMI8prs9EmuzSHOxQtnGDQ8EjLelWorGr2Z+2cDZq3/XuuIFawbsflrU+uomdHveteC/OMq45s2Mxv/ZAsk+iDor+T5htXN4kQ/nly4KOyIlhEAAAAAElFTkSuQmCC&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;Podcasts&quot; title src=&quot;/static/7b18a85a51d316e94a88e763493d4108/90cbd/resources-podcasts.png&quot; srcset=&quot;/static/7b18a85a51d316e94a88e763493d4108/29fe9/resources-podcasts.png 151w,
/static/7b18a85a51d316e94a88e763493d4108/6728c/resources-podcasts.png 303w,
/static/7b18a85a51d316e94a88e763493d4108/90cbd/resources-podcasts.png 605w,
/static/7b18a85a51d316e94a88e763493d4108/a2b88/resources-podcasts.png 908w,
/static/7b18a85a51d316e94a88e763493d4108/c1b63/resources-podcasts.png 1200w&quot; sizes=&quot;(max-width: 605px) 100vw, 605px&quot;&gt;
  &lt;/span&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://www.nytco.com/press/introducing-together-apart/&quot;&gt;
     &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 72.84768211920529%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAUDBv/EABUBAQEAAAAAAAAAAAAAAAAAAAID/9oADAMBAAIQAxAAAAHSZTmqnVgz/8QAGhAAAgMBAQAAAAAAAAAAAAAAAgMAAQQyEv/aAAgBAQABBQLWzy42sg86wu2ktlwef//EABYRAQEBAAAAAAAAAAAAAAAAABEBEP/aAAgBAwEBPwGBn//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/ASf/xAAdEAACAgEFAAAAAAAAAAAAAAAAAQIRISIxMkGB/9oACAEBAAY/AquW3RykvRFpZoegR//EABwQAQADAAIDAAAAAAAAAAAAAAEAESFhcTFB0f/aAAgBAQABPyFc5lLPPM1dOn9m+sjRzSG+tuDAoPjTIaPgn//aAAwDAQACAAMAAAAQeA//xAAWEQEBAQAAAAAAAAAAAAAAAAAxARD/2gAIAQMBAT8QdXP/xAAVEQEBAAAAAAAAAAAAAAAAAAAREP/aAAgBAgEBPxAE/8QAHhABAQABBAMBAAAAAAAAAAAAAREAITFRkUFhcYH/2gAIAQEAAT8QsxkQwa1sPXWAVt6dXdlq8cY1SqrK/Mdlhgg1Bv5gIVWmRwNxECIT1n//2Q==&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;podcast logo&quot; title src=&quot;/static/084813e763bd62363d4aac9bdcf85152/066f9/together-apart.jpg&quot; srcset=&quot;/static/084813e763bd62363d4aac9bdcf85152/0a254/together-apart.jpg 151w,
/static/084813e763bd62363d4aac9bdcf85152/c8fe0/together-apart.jpg 303w,
/static/084813e763bd62363d4aac9bdcf85152/066f9/together-apart.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
  &lt;/a&gt;
  &lt;p&gt;&lt;a href=&quot;https://www.nytco.com/press/introducing-together-apart/&quot;&gt;Together Apart&lt;/a&gt;, from &lt;em&gt;The New York Times&lt;/em&gt;&lt;/p&gt;
  &lt;blockquote&gt;On the first episode of &amp;#x201C;Together Apart,&amp;#x201D; we meet a woman who has been gathering for Passover Seder with over 40 people for 35 years and wants to know how to celebrate digitally without losing the intimacy. Priya helps her design a meaningful digital gathering by exploring one of the most important questions from the Passover tradition &amp;#x2014; what makes this night different from all other nights?&lt;/blockquote&gt;
&lt;/article&gt;
&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 18.543046357615893%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAAsSAAALEgHS3X78AAAAa0lEQVQI142OPQqAMBSDe32voSC4uNrNwdmi1p8iVOngFUTRl2fpBWy2BL4kggEGEQjAS2DvfRInUSkt+6UejRyM2lw9rZPdOXT8w+nsCm0zvZXzng82abrWHQGOWH7AN+EiPMD54gJT9O0PQ/fmZspvBTIAAAAASUVORK5CYII=&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;Tools&quot; title src=&quot;/static/a221cd22961241447113c968442e31a8/90cbd/resources-tools.png&quot; srcset=&quot;/static/a221cd22961241447113c968442e31a8/29fe9/resources-tools.png 151w,
/static/a221cd22961241447113c968442e31a8/6728c/resources-tools.png 303w,
/static/a221cd22961241447113c968442e31a8/90cbd/resources-tools.png 605w,
/static/a221cd22961241447113c968442e31a8/a2b88/resources-tools.png 908w,
/static/a221cd22961241447113c968442e31a8/c1b63/resources-tools.png 1200w&quot; sizes=&quot;(max-width: 605px) 100vw, 605px&quot;&gt;
  &lt;/span&gt;
&lt;article class=&quot;resource&quot;&gt;
  &lt;a class=&quot;img-link&quot; href=&quot;https://vito.community/more&quot;&gt;
     &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 72.84768211920529%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIDBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAAB2VaGlwCX/8QAGBABAQEBAQAAAAAAAAAAAAAAAgEAERL/2gAIAQEAAQUCSUZXZkLWJ6O//8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8BJ//EABYRAQEBAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPwFNJ//EABwQAAEEAwEAAAAAAAAAAAAAAAEAAiEiEBJBMf/aAAgBAQAGPwJoDa9KrOAdvOKKTj//xAAcEAACAgIDAAAAAAAAAAAAAAABIQAQEUExgZH/2gAIAQEAAT8hzYC6INnm6EsgPSHWTXdf/9oADAMBAAIAAwAAABBjz//EABYRAQEBAAAAAAAAAAAAAAAAAAEREP/aAAgBAwEBPxBRjn//xAAWEQEBAQAAAAAAAAAAAAAAAAABEEH/2gAIAQIBAT8QAEyf/8QAGRAAAgMBAAAAAAAAAAAAAAAAAREAITEQ/9oACAEBAAE/ELydtkxJc2pc0GeGQYbhg3x//9k=&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot;app logo&quot; title src=&quot;/static/021b14ed8277a734d83c16759f548071/066f9/vito.jpg&quot; srcset=&quot;/static/021b14ed8277a734d83c16759f548071/0a254/vito.jpg 151w,
/static/021b14ed8277a734d83c16759f548071/c8fe0/vito.jpg 303w,
/static/021b14ed8277a734d83c16759f548071/066f9/vito.jpg 400w&quot; sizes=&quot;(max-width: 400px) 100vw, 400px&quot;&gt;
  &lt;/span&gt;
  &lt;/a&gt;
  &lt;p&gt;
    &lt;a href=&quot;https://vito.community/more&quot;&gt;Vito&lt;/a&gt;
    &lt;span class=&quot;resource-description&quot;&gt;Vito is a platform for hosting live events that incorporates livestreaming, networked discussion, ticket sales, and a really thoughtful approach to privacy and inclusion. It&amp;#x2019;s being built by the folks at Hypertiny, with whom we collaborated on Brio conference back in 2013. They&amp;#x2019;re currently in beta, but you can read more about Vito on their &lt;a href=&quot;https://blog.tito.io/&quot;&gt;blog&lt;/a&gt;.&lt;/span&gt;
  &lt;/p&gt;
&lt;/article&gt;</content:encoded></item><item><title><![CDATA[Give your attendees the wheel]]></title><description><![CDATA[At one of our conferences, people walked into the venue on the first morning, and did what 99% of conference attendees do upon arriving at…]]></description><link>https://blog.andyet.com/2020/07/02/give-your-attendees-the-wheel/</link><guid isPermaLink="false">https://blog.andyet.com/2020/07/02/give-your-attendees-the-wheel/</guid><pubDate>Thu, 02 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This post is part of a series originally shared on &lt;a href=&quot;https://togetherness.is&quot;&gt;togetherness.is&lt;/a&gt;, a people-first resource for gathering remotely.&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/25/togetherness/&apos;&gt;Togetherness&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/26/sit-in-the-bad-seats/&apos;&gt;Sit in the bad seats&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/06/29/have-your-passports-ready/&apos;&gt;Have your passports ready&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Give your attendees the wheel&lt;/strong&gt; (You are here)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/07/09/recommended-resources/&apos;&gt;Recommended resources&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 52.317880794701985%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsSAAALEgHS3X78AAABtElEQVQoz1VRSVLCUBDlHJ7BA+gBPIxVytZyZ1mlR8AtZ2DBChaWkhAgQ1FMGaAIIQNDSBhC/k8I8UG01F4k/3f36/de/xwhRBTF5XJJKW02m2maHn9iOByyLCsK/EdLGKiqY9uyLDcajTiO03PkAO73+57nAcxxXAZDYTKZFAqFarWKhvV2S6MISdd1Lcv6B+71emBeLBaYstlsfN/Ht9vtVioVVHFFzTRNCJnP57iu12vkf5lRU1UVIwzDmE6nGcloNIKc7ABHEAzZ7XYbGU3TwjA8gUEC2XBeLBYdxwEtuuv1um3byKMJcxmGATPUSZI0Ho+R+WYGGHrQXSqVBoOB5/tYz9Pz813+XtG0XRjCPwDoiaIIMEyBoiRJchiMYSjXarVWqyWJ4mzmpMdD5LtGv6NrMgm2MaVYku95u91OEARFUVarFSAnMDh1XQeY5ThZEt565q2evFjJq3XIj6OHzizY76EOe4ERLAVnnufh/wQul8uwCp+8KIUL51EyLt7tK9a+Zu1LZnbzqRNKwaaoKt7JPUcQBNCSw6vil71tFkkcUxKSU4SUkMP5heEw85n+iS/1bxQQcqItcgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;a conference lanyard that says “attendee + co-organizer” next to a ticket, car keys, and pencils&quot;
        title=&quot;&quot;
        src=&quot;/static/82b2dea165980fd3a7e47c01dd8b4654/90cbd/give-your-attendees-the-wheel.png&quot;
        srcset=&quot;/static/82b2dea165980fd3a7e47c01dd8b4654/29fe9/give-your-attendees-the-wheel.png 151w,
/static/82b2dea165980fd3a7e47c01dd8b4654/6728c/give-your-attendees-the-wheel.png 303w,
/static/82b2dea165980fd3a7e47c01dd8b4654/90cbd/give-your-attendees-the-wheel.png 605w,
/static/82b2dea165980fd3a7e47c01dd8b4654/a2b88/give-your-attendees-the-wheel.png 908w,
/static/82b2dea165980fd3a7e47c01dd8b4654/c1b63/give-your-attendees-the-wheel.png 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;At one of our conferences, people walked into the venue on the first morning, and did what 99% of conference attendees do upon arriving at the venue: they looked around for a cup of coffee.&lt;/p&gt;
&lt;p&gt;They didn’t find any. There wasn’t a single chrome-and-black-plastic, thermal-insulated canister to be found. &lt;/p&gt;
&lt;p&gt;Who the heck puts together a conference and forgets to brew coffee? &lt;/p&gt;
&lt;p&gt;Then someone spotted the Chemex. It was sitting on one of the round tables at which we’d seated the participants, like an empty flower vase. They picked it up and looked around. Several strangers began to conspire together. Now it was a quest.&lt;/p&gt;
&lt;p&gt;Someone else found a coffee grinder - a hand-powered one. (What the heck?) At another table, filters. The carafe a couple of tables over was, it turned out, filled with piping hot water. Finding the beans took a little more effort: those turned up deep inside the swag boxes, under a layer of tissue paper.&lt;/p&gt;
&lt;p&gt;All this only took a few minutes. It wasn’t a formal exercise, at least not the kind we’re used to at conferences. There was surprise, laughter, frustration, collaboration… an easy excuse for &lt;a href=&quot;/2020/06/29/have-your-passports-ready/&quot;&gt;conversation with strangers&lt;/a&gt; (a bonus for more introverted attendees)… and, of course, really good coffee. &lt;/p&gt;
&lt;p&gt;But more than that — and this was our real goal in setting up the DIY coffee hunt — it was a small, practical way of turning everyone present into a co-organizer of the event. &lt;/p&gt;
&lt;p&gt;Whose job is it to make coffee? Typically, that responsibility falls to the hosts. Who has free run of the room, the right to move things off of the tables — to make a bit of a mess grinding coffee beans? &lt;/p&gt;
&lt;p&gt;Each of these actions is small, but as attendees took them, they created a significant shift, from passive to active, from observer to participant — from “Who’s in charge?” to “I suppose I am.”&lt;/p&gt;
&lt;h2 id=&quot;small-actions-huge-impact&quot;&gt;&lt;a href=&quot;#small-actions-huge-impact&quot; aria-label=&quot;small actions huge impact permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Small actions; huge impact.&lt;/h2&gt;
&lt;p&gt;When participants feel a sense of agency — that they have the power to influence the way the event runs — three things happen.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Their investment goes up.&lt;/strong&gt; If “you get out what you put in” is true, they’ll get a lot more out of the event than they would have otherwise. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deeper bonds form.&lt;/strong&gt; They’ll remember the person who helped them find the coffee grinder, and the experience of hunting around with them. These kinds of shared moments are the seeds from which future relationships (business, personal, or otherwise) sprout. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You, the organizer, learn far more.&lt;/strong&gt; Participants will give you more candid — and richer — feedback on your event, because they feel empowered to do so. This results in better learning, that you can apply to future events. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can help cultivate a sense of co-ownership by giving them the wheel, so to speak — not just “inviting input,” but literally putting your attendees in charge of things. Even seemingly small things, like making their own coffee from component parts, can have an outsized impact on everyone’s experience, and make the event extraordinary.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;its-not-really-about-the-coffee-of-course&quot;&gt;&lt;a href=&quot;#its-not-really-about-the-coffee-of-course&quot; aria-label=&quot;its not really about the coffee of course permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It’s not really about the coffee, of course.&lt;/h2&gt;
&lt;p&gt;We once gave everyone unsharpened pencils to write with, and set up a communal pencil sharpening table with an old-fashioned manual sharpener that required someone to turn the handle.&lt;/p&gt;
&lt;p&gt;We’ve invited empathetic, extroverted attendees to serve as ‘table hosts’ for a pre-event breakfast and lunch during the conference, inviting them to lead conversations and facilitate introductions between attendees.&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;http://2013.brioconference.com/&quot;&gt;Brio&lt;/a&gt;, we had participants shuffle seats at the conclusion of each talk, while the speaker set up an activity or a question for discussion. &lt;/p&gt;
&lt;p&gt;We’ve kicked off conferences by having everyone raise their hands, and deputizing every attendee as a co-organizer of the event. We welcomed them to the organizing team, and gave them three important responsibilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;to recognize the impact their participation would have on everyone else’s experience;&lt;/li&gt;
&lt;li&gt;to bring the best of their attention, thought, care, and reflection; and&lt;/li&gt;
&lt;li&gt;to share their input on how to make the event better.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The principle behind all of these exercises was simply this: to create space for our attendees to co-create the event with us, to invite them to be co-leaders, and to give them opportunities to engage as fully as they wanted to with the experience. &lt;/p&gt;
&lt;p&gt;For remote gatherings, we believe this is an even more crucial principle, because deep engagement is harder when we aren’t sharing physical space with each other. Our ability to pick up subtle cues and suss each other out is hampered by clumsy and imperfect technologies, and of course we can’t do the same kinds of collaborative building activities we might do IRL. &lt;/p&gt;
&lt;p&gt;However, there are still lots of ways we can design remote events to put attendees at the center, and bring their most creative and collaborative selves to the table. &lt;/p&gt;
&lt;h2 id=&quot;how-can-you-give-your-attendees-the-wheel&quot;&gt;&lt;a href=&quot;#how-can-you-give-your-attendees-the-wheel&quot; aria-label=&quot;how can you give your attendees the wheel permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How can you give your attendees the wheel?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;What “loose parts” could your attendees help to assemble?&lt;/li&gt;
&lt;li&gt;What opportunities can you provide for them to actively engage in the planning, design, and implementation of the event?&lt;/li&gt;
&lt;li&gt;How might you deputize your attendees, in order to more effectively engage their hearts, minds, and contributions?&lt;/li&gt;
&lt;li&gt;How could you get your attendees collaborating and co-creating with each other?&lt;/li&gt;
&lt;li&gt;What “standard-issue” elements of your event are prime candidates for a rethink? How might you redesign them in more engaging, participatory, and thoughtful ways?&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Check out the next post in the Togetherness series: &lt;a href=&quot;/2020/07/09/recommended-resources/&quot;&gt;Recommended resources&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Have your passports ready]]></title><description><![CDATA[Three truths — two that are probably self-evident, and one learned through experience:Few things in life expand a person’s mind more…]]></description><link>https://blog.andyet.com/2020/06/29/have-your-passports-ready/</link><guid isPermaLink="false">https://blog.andyet.com/2020/06/29/have-your-passports-ready/</guid><pubDate>Mon, 29 Jun 2020 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This post is part of a series originally shared on &lt;a href=&quot;https://togetherness.is&quot;&gt;togetherness.is&lt;/a&gt;, a people-first resource for gathering remotely.&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/25/togetherness/&apos;&gt;Togetherness&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/26/sit-in-the-bad-seats/&apos;&gt;Sit in the bad seats&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Have your passports ready&lt;/strong&gt; (You are here)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/07/02/give-your-attendees-the-wheel/&apos;&gt;Give your attendees the wheel&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/07/09/recommended-resources/&apos;&gt;Recommended resources&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 52.317880794701985%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsSAAALEgHS3X78AAABiElEQVQoz1WSaW6CYBCGOUBv0/P0RO0NeosewMQdBGtcKHHFDYkWFfhAULY+akzb+UEmL/MuMyCt1+tarRZFked5juNst1vXdReLxX6/94WIhf+5895XwjAXSrNZFMVyudztdszQS7PZrNfr0V0uFwhCiPP5fDgcwjAEydL0xcyeuvnrPJh0tDhJR6NREARMXsmmaXY6HZyh4YwkHLRvQkEk/Dfr8vyVftiBrrUgEAq/NE1/ybgR+3Q6geZ5Dvl4PDrO3ve8c5KINA/DQNM0Bubz+Xg8xiOO4yu52+0igzlMDGFyCF4T3vW8uwlR8QAfDAaQh8MhZhJK7Xb7+1a803Xdtu3pZMoWEO5x2B9RVVXRXT6KAYkdFEXp9/s06GmqSrPZbAiSZRlM3+fqAnK1WuVbkIK9uAsHusaWZZkntpZlGYYBigNukJFAiFCr1apUKjEACBNRQInFQFutlnwrGuKVy+VGo0FPKP6Cer1eqVT4ottHsRpHkYiRJAlK0Z/ikn/7e5G2+F8/9hIfWSGMb2MAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;an open passport with plenty of stamps next to a stamp and inkpad&quot;
        title=&quot;&quot;
        src=&quot;/static/6be59d7de7e7db51457e85ff9401c4ac/90cbd/have-your-passports-ready.png&quot;
        srcset=&quot;/static/6be59d7de7e7db51457e85ff9401c4ac/29fe9/have-your-passports-ready.png 151w,
/static/6be59d7de7e7db51457e85ff9401c4ac/6728c/have-your-passports-ready.png 303w,
/static/6be59d7de7e7db51457e85ff9401c4ac/90cbd/have-your-passports-ready.png 605w,
/static/6be59d7de7e7db51457e85ff9401c4ac/a2b88/have-your-passports-ready.png 908w,
/static/6be59d7de7e7db51457e85ff9401c4ac/c1b63/have-your-passports-ready.png 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Three truths — two that are probably self-evident, and one learned through experience:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Few things in life expand a person’s mind more immediately, concretely, and lastingly than traveling somewhere unfamiliar, and immersing oneself in the experience.&lt;/li&gt;
&lt;li&gt;If you want creativity, innovation, and fresh perspectives, your best bet is to bring together a diverse group of people.&lt;/li&gt;
&lt;li&gt;If you want that diverse group of people to actually &lt;em&gt;experience&lt;/em&gt; creativity, innovation, and fresh perspectives, you need to create scaffolding for meaningful “cross-border” experiences, and that requires care and effort. &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That third point spurred us to do some things that were maybe a little weird, but ultimately impactful, at our live conferences. More on that in a moment, but for now, suffice it to say it involved actual passport booklets and one-of-a-kind stamps for every attendee. &lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;We’ve always felt that the most memorable and meaningful events bring together people who see things differently. This has been a through-line for all of the conferences and workshops &amp;#x26;yet has convened: bringing together people from varied disciplines, backgrounds, and walks of life to learn from each other. &lt;/p&gt;
&lt;p&gt;The particular mix of people has been unique to each event’s purpose and context. But whether we brought together various kinds of technologists under one roof, or got artists, designers, coders, activists, and business people to share a table, the results were the very definition of a whole greater than its parts: new projects were spawned, close friendships formed, and career trajectories changed. &lt;/p&gt;
&lt;p&gt;There’s nothing wrong with bringing together people with a common set of backgrounds, experiences, and interests, of course — particularly if those people rarely have opportunities to share space with others like them. But it seems to us that one of the core purposes of gathering people is to get people out of being stuck in their bubbles. &lt;/p&gt;
&lt;p&gt;Most of us tend to gravitate, by default, towards spending time with people who seem familiar and similar to us — it takes effort to push back against that gravitational pull. &lt;strong&gt;But when we get stuck in familiar bubbles, we get stuck in a pretty homogeneous version of reality.&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;Some of the most important learning we’ll do in our lifetimes will happen through exposure to unfamiliar perspectives. The only way we can access those perspectives is by meeting people who are different from ourselves, and learning enough about how they see the world that we open up our own mindset and point of view. &lt;/p&gt;
&lt;h2 id=&quot;our-task-as-event-organizers-is-to-offer-people-experiences-that-they-cant-or-are-unlikely-to-have-on-their-own-in-their-everyday-lives&quot;&gt;&lt;a href=&quot;#our-task-as-event-organizers-is-to-offer-people-experiences-that-they-cant-or-are-unlikely-to-have-on-their-own-in-their-everyday-lives&quot; aria-label=&quot;our task as event organizers is to offer people experiences that they cant or are unlikely to have on their own in their everyday lives permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Our task as event organizers is to offer people experiences that they can’t (or are unlikely to) have on their own, in their everyday lives.&lt;/h2&gt;
&lt;p&gt;One of the most valuable experiences we can facilitate for our attendees is to provide them with paths to building trust and exchanging ideas with people who aren’t just like them. But you can’t just throw together a bunch of people with disparate experiences and points of view and expect magical outcomes — at least, not with any consistency. &lt;strong&gt;If you’re trying to build bridges, you need to create &amp;#x26; facilitate them.&lt;/strong&gt; &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The leadership task is to bring the gifts of those on the margin into the center” –Peter Block, Community: The Structure of Belonging&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;where-do-you-come-from-where-have-you-been&quot;&gt;&lt;a href=&quot;#where-do-you-come-from-where-have-you-been&quot; aria-label=&quot;where do you come from where have you been permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Where do you come from? Where have you been?&lt;/h2&gt;
&lt;p&gt;In 2012, while organizing the second RealtimeConf — a conference aimed at bringing together folks doing “JavaScript mad science” and open standards folks who had been detailing protocols and writing specs for decades — we landed on the notion that we could use elements of imagination and play to help forge connections between the people coming to the event. Since the two groups were very different culturally, but had lots to learn from and share with each other, we decided to invent a variety of &lt;a href=&quot;https://www.instagram.com/p/fnacEPsMzg/?igshid=xsx1axv6g4g0&quot;&gt;fictional countries,&lt;/a&gt; and assigned each attendee to a particular &lt;a href=&quot;https://www.instagram.com/p/RJRxRplJgf/?igshid=mns4s9xis7gn&quot;&gt;nation&lt;/a&gt;, with its own flag and cultural markers. &lt;/p&gt;
&lt;p&gt;As attendees arrived at the conference venue, they received &lt;a href=&quot;https://www.flickr.com/photos/andyet-photos/10352698783/in/album-72157636702378244/&quot;&gt;passports&lt;/a&gt; (and the following year, we included &lt;a href=&quot;https://www.flickr.com/photos/andyet-photos/10353010613/in/album-72157636702378244/&quot;&gt;letters of welcome from the fictional head of state of their nation&lt;/a&gt; — yes, we went all the way there), and were encouraged to visit as many of the other “countries” as they could, collecting &lt;a href=&quot;https://www.instagram.com/p/fnqrpArDHU/?igshid=1o06m1hakvee4&quot;&gt;stamps&lt;/a&gt;. Aside from introducing a playful and disarming exercise (an important pursuit in itself), we wanted to give attendees a shared experience of realizing some key truths: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We need each other;&lt;/li&gt;
&lt;li&gt;We need to explore and learn each other’s cultures;&lt;/li&gt;
&lt;li&gt;This conference was for “international” people — i.e. your &lt;em&gt;goal&lt;/em&gt; is to travel around and interact with people from different nations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.instagram.com/p/8ipC09Jv5L/?igshid=om442enlz0ha&quot;&gt;passports&lt;/a&gt; served as a physical reminder of those truths, and of the event’s &lt;a href=&quot;https://2013.realtimeconf.com/#mission&quot;&gt;mission&lt;/a&gt; — and they succeeded in acting as the bridge people needed to reach out and make connections with people different from them. They were the excuse people needed to talk about where they came from, where they had been, and where they intended to go next. And most importantly, to talk across, and through, differences — not only looking for common ground, but actively seeking to expand their own thinking. &lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;Our passports were physical — and so were &lt;a href=&quot;https://www.instagram.com/p/fnwGIgjKCR/?igshid=11lha0g2qnuxf&quot;&gt;the stamps each attendee received&lt;/a&gt;, to stamp each other’s passports with. But as we shift into convening people remotely, we’re exploring how we might include some infrastructure that encourages participants to view their differences with a sense of play, and to actively seek out opportunities to connect. &lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;Here are a few questions you can ask yourself as you’re planning your event: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What bubbles do we see forming in our communities? What bubbles might benefit from connecting with each other?&lt;/li&gt;
&lt;li&gt;Who can we bring in to give new perspectives by dint of their participation?&lt;/li&gt;
&lt;li&gt;How can we go beyond the perspectives we’re seeing in our corner of the internet?&lt;/li&gt;
&lt;li&gt;How can we cultivate diversity along multiple lines: intellectual, cultural, and social diversity, as well as race, gender, ability, etc.?&lt;/li&gt;
&lt;li&gt;Who can we reach out to, to help us reach out several degrees of connection outside our own bubbles? &lt;/li&gt;
&lt;li&gt;What are some concrete ways we can encourage bridge-building among attendees? How can we make it easier, and more fun, for them to learn about one another, and celebrate their differences? &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Check out the next post in the Togetherness series: &lt;a href=&quot;/2020/07/02/give-your-attendees-the-wheel/&quot;&gt;Give your attendees the wheel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Sit in the bad seats]]></title><description><![CDATA[You can have the most incredible programming, and the perfect group of people, but if the chairs are uncomfortable or sight lines are…]]></description><link>https://blog.andyet.com/2020/05/26/sit-in-the-bad-seats/</link><guid isPermaLink="false">https://blog.andyet.com/2020/05/26/sit-in-the-bad-seats/</guid><pubDate>Tue, 26 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This post is part of a series originally shared on &lt;a href=&quot;https://togetherness.is&quot;&gt;togetherness.is&lt;/a&gt;, a people-first resource for gathering remotely.&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/25/togetherness/&apos;&gt;Togetherness&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Sit in the bad seats&lt;/strong&gt; (You are here)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/06/29/have-your-passports-ready/&apos;&gt;Have your passports ready&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/07/02/give-your-attendees-the-wheel/&apos;&gt;Give your attendees the wheel&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/07/09/recommended-resources/&apos;&gt;Recommended resources&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 52.317880794701985%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsSAAALEgHS3X78AAABiUlEQVQoz22Ra26CUBCF2UZX2V20++giTBoTk6Y1NRWiQcArb1CxvoD6AKWC/YSmv3oSJnMvc+bMPSOdz+fvGpvNpigKjiTH47Esy68a1+vV9/3tdpskyX6/T9O0qqqihgQtz/Msy1arFZzD4UCy2+1Op9O2xuVy8TwvjuP1ek0vbvIadJdoDLOpbgjk3FBHpIiO0+kU2XAeoU4vBPgFUaJlEAT0Ho/HJNRpmmZZ1mKxMAyDy+VyORgMIMeh/+k7hhCB71MJUQrDUNd1OK1WixzlTqcDh/Zw+rKMC6YQaZI82MmTmL22n70gEEJQLDUKzDYajbrd7nw+Z9Rer4d+XOP9o//WV9Ld/u5led+WI1PkRaEoCrNIfDhk23YURcPh0HXd2Ww2mUxM02Q2fBamOdR0zXYe31THspoCIk7fDGNUHsl4rAFBRsBJ9FVVlWWZnCXohqEqclWVxyzjmezsZhgfG+PNFOEz9jiOwyY5kqBQ1vBc9+8ed4m/ZMAMRNbA7yY2yb95Uwx+AHdSI9cxfAVBAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;an audience sits in a theater an unamused audience member cranes their neck around a pole blocking their view&quot;
        title=&quot;&quot;
        src=&quot;/static/d8380ca296b9e52f9554e94405c9e567/90cbd/sit-in-the-bad-seats.png&quot;
        srcset=&quot;/static/d8380ca296b9e52f9554e94405c9e567/29fe9/sit-in-the-bad-seats.png 151w,
/static/d8380ca296b9e52f9554e94405c9e567/6728c/sit-in-the-bad-seats.png 303w,
/static/d8380ca296b9e52f9554e94405c9e567/90cbd/sit-in-the-bad-seats.png 605w,
/static/d8380ca296b9e52f9554e94405c9e567/a2b88/sit-in-the-bad-seats.png 908w,
/static/d8380ca296b9e52f9554e94405c9e567/c1b63/sit-in-the-bad-seats.png 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;You can have the most incredible programming, and the perfect group of people, but if the chairs are uncomfortable or sight lines are compromised, you’ll lose people. &lt;/p&gt;
&lt;p&gt;This is both literally true and a metaphor.&lt;/p&gt;
&lt;p&gt;When we had finished setting up our ambitious three-day musical theatre and JavaScript training experience, &lt;a href=&quot;/2014/03/07/introducing-js-for-teams/&quot;&gt;&lt;em&gt;JS for Teams: “It’s ALIIIIIIIVE!”&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; one of our team said members, “Hold on, let’s do one last thing.” &lt;/p&gt;
&lt;p&gt;The team went around the room and sat in every seat, gauging the quality of the experience from different vantage points. The team spent extra time sitting in what they’d discerned were the worst seats. Once they’d gotten a feel for how the people in those seats were going to experience the event, the team changed the whole setup of the room.&lt;/p&gt;
&lt;p&gt;The event is only as good as it feels from the worst seats. People shouldn’t have to luck into a good seat to have the best possible experience. &lt;/p&gt;
&lt;p&gt;This is every bit as true in a remote context. You may not be able to control the kind of chairs your participants are sitting in, but you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;spend some time thinking about how the experience will feel from the equivalent of “the nosebleed section”: low bandwidth, small screen, home office, etc. &lt;/li&gt;
&lt;li&gt;send out a list of recommendations for optimizing their experience — what would make it easier for people to have the equivalent of a good view, a comfortable seat, a place to settle in? &lt;/li&gt;
&lt;li&gt;allow time at the beginning of the event to walk people through any adjustments they can make, to have a more comfortable, rich, immersive experience.&lt;/li&gt;
&lt;li&gt;think about what their different ‘seats’ might be and ask about the experience from that perspective, like: “What will the experience be for people who are going to be distracted because they’re also caring for kids?”&lt;/li&gt;
&lt;li&gt;do everything in your power to make your event as accessible as possible – think live captioning, clear descriptions for visual content, written transcripts/shared notes, and so on. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A bad chair decision can ruin your whole event — and that’s not hyperbole. We once neglected to test a venue’s gorgeous wood chairs thoroughly; the chairs created beautiful, clean, modern lines in the room, and they seemed fine at first. But after thirty minutes of sitting on them, it became apparent that the seats were so flat and uncomfortable that some people’s legs had fallen asleep. The chairs became a distraction, and detracted significantly from everyone’s enjoyment and ability to focus.&lt;/p&gt;
&lt;p&gt;That was an utter seating failure — though in retrospect, it was probably the seed of how we ended up with only couches and comfy chairs at &lt;a href=&quot;https://andyetconf.com/&quot;&gt;&amp;#x26;yetConf&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For us, “sit in the bad seats” signifies a bunch of related, crucial, and often overlooked things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The basics matter more than you think.&lt;/strong&gt; Nourishing snacks, good water, comfortable seating, the temperature of the room — they all contribute significantly to your event’s success.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make sure every seat is a good seat.&lt;/strong&gt; Use whatever factors are in your control to ensure everyone in attendance is having the best possible experience. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sometimes the literal is the best path to the figurative.&lt;/strong&gt; Want to put yourself in your attendees’ shoes? Try sitting in their actual seats. &lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Check out the next post in the Togetherness series: &lt;a href=&quot;/2020/06/29/have-your-passports-ready/&quot;&gt;Have your passports ready&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Togetherness]]></title><description><![CDATA[Many of our favorite gatherings have had to move online, from conferences and live performances, to team meetings and birthday celebrations…]]></description><link>https://blog.andyet.com/2020/05/25/togetherness/</link><guid isPermaLink="false">https://blog.andyet.com/2020/05/25/togetherness/</guid><pubDate>Mon, 25 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This post is part of a series originally shared on &lt;a href=&quot;https://togetherness.is&quot;&gt;togetherness.is&lt;/a&gt;, a people-first resource for gathering remotely.&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Togetherness&lt;/strong&gt; (You are here)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/26/sit-in-the-bad-seats/&apos;&gt;Sit in the bad seats&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/06/29/have-your-passports-ready/&apos;&gt;Have your passports ready&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/07/02/give-your-attendees-the-wheel/&apos;&gt;Give your attendees the wheel&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/07/09/recommended-resources/&apos;&gt;Recommended resources&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 53.64238410596026%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABx0lEQVQoz32Sy4riQBSGs3Htwo0r0bW48il8BXeC4MqXcOFLiDSICx2v4B1UFBRRB1tn3IjXTqftHibBTky01VRl/iRNzzA9zL+oHE6d7/x1qsKUy+VKpdLv9w+Hg6ZplFJN/+gRVkqM2JCqqpvNBsWlUqlWq9XrdaZQKHQ6nWazuV6v/+IpeeeoQXIcNx6Pu91uu93OZDKpVIrJ5XKNRqNYLCaTSe6R0x0mP69feT77zN69PPTkwUj+/uOGfKvVAgBPOGez2clkwiwWCxgiVa1WHx/YC72Rb4KS3Ahfnl5nirA8v4pEPN8kSby/n8JjNpvt9/vtdouzMJfLBV0VRTmdTvP5fLlc6udU6ceo0PV6HQ6HPM8fj0fVEDLIM7IsvxkCj/hZ1wuh9KZLJYQiiWlBgpEkCStawEmHR6OR6SwIwnQ6Xa1WqDj/IWyBxIQsy4qiiOtEO5xfv+1wOByPx/1+fyQSGQwG2ieZl4/W6XQ6FAqhPpFIeDwei8XC2O12m80WDAZ3u51Z+v5Un3hCSD6f93q9VqvV5XK53W4GPWKxGCb5/cL/ErYAI8DvEAgEHA6H0+lker2e2fU/5IdMHg8UjUZ9Pt8vIqEwvWYmjEcAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Togetherness logo in handwritten lettering with geometric tree and root shapes surrounding&quot;
        title=&quot;&quot;
        src=&quot;/static/877a5cc399c5fbfd28822da7993ad889/90cbd/togetherness.png&quot;
        srcset=&quot;/static/877a5cc399c5fbfd28822da7993ad889/29fe9/togetherness.png 151w,
/static/877a5cc399c5fbfd28822da7993ad889/6728c/togetherness.png 303w,
/static/877a5cc399c5fbfd28822da7993ad889/90cbd/togetherness.png 605w,
/static/877a5cc399c5fbfd28822da7993ad889/a2b88/togetherness.png 908w,
/static/877a5cc399c5fbfd28822da7993ad889/a3767/togetherness.png 1210w,
/static/877a5cc399c5fbfd28822da7993ad889/7d62e/togetherness.png 2368w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Many of our favorite gatherings have had to move online, from conferences and live performances, to team meetings and birthday celebrations. We’re suddenly being forced to adapt IRL events to work in new contexts – and in the process, we’re waking up to just how much is baked into those IRL gatherings that we may have taken for granted:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Surprise, serendipity, or a shared laugh with someone sitting nearby&lt;/li&gt;
&lt;li&gt;The shared rhythm of a day’s activities&lt;/li&gt;
&lt;li&gt;Physical space – architecture, landscape, and how it feels to be in a particular location&lt;/li&gt;
&lt;li&gt;The particular quality of connecting with like-minded people, and maybe making new friends, while sharing space with each other&lt;/li&gt;
&lt;li&gt;Feeling a sense of belonging in a community&lt;/li&gt;
&lt;li&gt;Having the opportunity to meet someone we respect&lt;/li&gt;
&lt;li&gt;Enjoying a once-in-a-lifetime experience, and making memories&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Can you recreate all of those experiences within a remote context?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Maybe not. But if we dig into &lt;em&gt;how&lt;/em&gt; those experiences are created, they certainly don’t all rely exclusively on sharing physical space. It is possible to make remote gatherings far more meaningful than they usually are. It’s possible for us to feel truly &lt;em&gt;together&lt;/em&gt;, even when we’re apart.&lt;/p&gt;
&lt;p&gt;Our team knows this for sure, because while we’ve convened some of the most emotionally stirring, &lt;a href=&quot;https://experience.realtimeconf.com/&quot;&gt;unforgettable conferences&lt;/a&gt; the tech world has experienced, we’re also a &lt;a href=&quot;https://andyet.com/about&quot;&gt;remote team&lt;/a&gt; that holds stirring, unforgettable &lt;a href=&quot;/2019/01/11/bts-a-remote-holiday-party/&quot;&gt;virtual parties&lt;/a&gt; to celebrate with each other. We’ve worked with clients to design software demos for live events that foster connection and shared laughter – and to connect people before an event through vivid, immersive storytelling.&lt;/p&gt;
&lt;h2 id=&quot;weve-always-been-100-sold-on-the-magic-of-live-events-and-we-also-span-roleimg-aria-labelpurple-heartspan-the-good-things-the-web-makes-possibleespecially-finding-and-connecting-with-your-people-across-any-distance&quot;&gt;&lt;a href=&quot;#weve-always-been-100-sold-on-the-magic-of-live-events-and-we-also-span-roleimg-aria-labelpurple-heartspan-the-good-things-the-web-makes-possibleespecially-finding-and-connecting-with-your-people-across-any-distance&quot; aria-label=&quot;weve always been 100 sold on the magic of live events and we also span roleimg aria labelpurple heartspan the good things the web makes possibleespecially finding and connecting with your people across any distance permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;We’ve always been 100% sold on the magic of live events. And we also &lt;span role=&quot;img&quot; aria-label=&quot;purple heart&quot;&gt;💜&lt;/span&gt; the good things the web makes possible—especially finding and connecting with your people across any distance.&lt;/h2&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;There are a lot of generous folks helping by sharing knowledge about different aspects of remote work and remote events right now.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We’re seeing technical how-to’s on how to transpose the essential functions of IRL gatherings as efficiently as possible into our new context – what software to use, what settings to employ, and so on.&lt;/li&gt;
&lt;li&gt;Schools and universities are migrating en masse to remote learning, and students and faculty are experiencing first-hand what the intangible benefits are of being on a campus, vs a classroom that’s been transposed into Zoom or Canvas. Educators are sharing best practices and resources for facilitating learning in a remote context.&lt;/li&gt;
&lt;li&gt;People with experience working remotely are sharing their home office setups and routines, their hard-won insights into how to maintain healthy boundaries, good posture, and navigate communication challenges.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our focus is a little different than all of these excellent resources.&lt;/p&gt;
&lt;h2 id=&quot;were-interested-in-how-we-can-experience-more-togetherness-across-distances&quot;&gt;&lt;a href=&quot;#were-interested-in-how-we-can-experience-more-togetherness-across-distances&quot; aria-label=&quot;were interested in how we can experience more togetherness across distances permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;We’re interested in how we can experience more &lt;em&gt;togetherness&lt;/em&gt; across distances.&lt;/h2&gt;
&lt;p&gt;We want to share some of what we’ve learned from over a decade of bringing people together IRL and remotely, using creative technology to touch people emotionally, and fostering a whole-self workplace here at &amp;#x26;yet where most of us are accustomed to sharing our home offices with kids, pets, and other family members.&lt;/p&gt;
&lt;p&gt;We want to talk about what’s truly irreplaceable about IRL events, while also digging into how we might use our creativity to make remote gatherings just as special, memorable, valuable, and meaningful.&lt;/p&gt;
&lt;p&gt;Like you, we’re acutely missing handshakes and hugs, traveling to meet people in person, and the serendipity of running into someone we haven’t seen for years at the coffee shop. We can’t wait to get those things back.&lt;/p&gt;
&lt;p&gt;And we’re also pretty certain that our new reality is going to involve more remote gatherings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So let’s talk about how togetherness works, how we can cultivate more of it, and make the absolute most out of our time together.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Check out the next post in the Togetherness series: &lt;a href=&quot;/2020/05/26/sit-in-the-bad-seats/&quot;&gt;Sit in the bad seats&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Flexibility]]></title><description><![CDATA[An exercise in flexibility and making plans when so many circumstances are beyond your control.
    Your browser does not support the…]]></description><link>https://blog.andyet.com/2020/05/06/flexibility/</link><guid isPermaLink="false">https://blog.andyet.com/2020/05/06/flexibility/</guid><pubDate>Wed, 06 May 2020 11:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This exercise is part of a series originally shared on &lt;a href=&quot;https://gatherthecourage.com&quot;&gt;Gather the Courage&lt;/a&gt;, guided journaling for creative leaders to reflect, be encouraged, and make courageous decisions.&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/03/18/spaciousness/&apos;&gt;Spaciousness&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/06/groundedness/&apos;&gt;Groundedness&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Flexibility&lt;/strong&gt; (You are here)&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;An exercise in flexibility and making plans when so many circumstances are beyond your control.&lt;/p&gt;
&lt;p&gt;&lt;audio
  preload=&quot;metadata&quot;
  controls
  src=&quot;/flexibility-9050558da821efcd2961dae2fe3f9675.mp3&quot;&gt;
Your browser does not support the
&lt;code&gt;audio&lt;/code&gt; element.
&lt;/audio&gt;&lt;/p&gt;
&lt;br&gt;
&lt;h3 id=&quot;transcript&quot;&gt;Transcript:&lt;/h3&gt;
&lt;p&gt;Let’s start by settling in. Make sure you’re sitting in a comfortable position for writing, and that you have your notebook and pen handy. Take a moment to breathe as you find something to appreciate right now. Do you see something beautiful? Do you feel a sense of energy or calm? What is it that is unique about this moment?&lt;/p&gt;
&lt;p&gt;If you can’t think of anything, it’s okay. It’s really good that you’re here, and I appreciate you doing this exercise with me, no matter what else is going on.&lt;/p&gt;
&lt;p&gt;Now that you’ve settled in, let’s set our purpose for this time. As I’m recording this, our world is changing in response to the COVID-19 pandemic. We aren’t quite sure how it will unfold, but we know that nothing is the same as it was a month ago, or even last week.&lt;/p&gt;
&lt;p&gt;As a leader, this is affecting you in a unique way. You may have a vision you’ve been working toward seem suddenly irrelevant. You may be wondering if your plans are still workable.
Because of this, today, my intention is to walk you through an exercise in flexibility. It can be challenging to hold your plans loosely when circumstances change that are beyond your control. We are going to explore your relationship with your existing vision and plans and see where you might allow for more flexible thinking.&lt;/p&gt;
&lt;p&gt;Now it’s time to write. What is one challenge or difficulty you’ve been thinking about lately? Spend a few minutes free-writing about problems you’ve been trying to solve, and choose one to focus on. Give yourself permission to free-write whatever comes to mind. I’ll check back in in a few minutes.&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;How’s it going? If you need more time, feel free to press pause and continue writing. Whenever you’re ready, think about one challenge or problem you’ve been considering. You can do this exercise again later if you have more than one you’re trying to figure out, but for now, just focus on one.&lt;/p&gt;
&lt;p&gt;One gift of practicing flexibility is realizing that even though your problems are certainly a challenge for you, they are not only a challenge. It is easy to acknowledge the challenge and try to overcome it, but there is also a seed of goodness inside of each and every situation we face. What is the seed of goodness in this particular problem? Take a few minutes to consider what that seed of goodness could be. I’ll be back in a few minutes to check in.&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;Were you able to find the seed of goodness yet? If not, that’s okay. One seed of goodness this challenge might have for you is that it gives you the opportunity to practice flexibility.&lt;/p&gt;
&lt;p&gt;Now as you think about both the challenge and its seed of goodness, what does your gut say to do with this challenge?&lt;/p&gt;
&lt;p&gt;Maybe there is an action you know you need to take, or maybe there is nothing you can do right now, and you need to let it sit and move on to something else. Maybe you need to learn more, or talk to someone.&lt;/p&gt;
&lt;p&gt;I’ve found it easiest to listen to my gut when I begin my writing with the phrase “The truth is...” You might try it. What does your gut say to do with this challenge? Start by writing “The truth is...” and then keep writing whatever comes to mind. I’ll be back in a few minutes.&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;That question may have been challenging, or it may have opened you up to a new possibility you hadn’t considered. Whatever the outcome, don’t worry about needing to have all the answers right now. You can do this exercise whenever you need more clarity around the options available to you. &lt;/p&gt;
&lt;p&gt;Practicing flexibility helps us find solutions to challenges we may have never considered. Or we may see that they are not challenges after all, and we can either embrace them or let them go.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Groundedness]]></title><description><![CDATA[An exercise to help you feel grounded, despite what might be happening around you.
    Your browser does not support the
    audio element…]]></description><link>https://blog.andyet.com/2020/05/06/groundedness/</link><guid isPermaLink="false">https://blog.andyet.com/2020/05/06/groundedness/</guid><pubDate>Wed, 06 May 2020 10:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This exercise is part of a series originally shared on &lt;a href=&quot;https://gatherthecourage.com&quot;&gt;Gather the Courage&lt;/a&gt;, guided journaling for creative leaders to reflect, be encouraged, and make courageous decisions.&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/03/18/spaciousness/&apos;&gt;Spaciousness&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Groundedness&lt;/strong&gt; (You are here)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/06/flexibility/&apos;&gt;Flexibility&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;An exercise to help you feel grounded, despite what might be happening around you.&lt;/p&gt;
&lt;p&gt;&lt;audio
  preload=&quot;metadata&quot;
  controls
  src=&quot;/groundedness-933db40f7f5b385214226d06ae50dcb8.mp3&quot;&gt;
Your browser does not support the
&lt;code&gt;audio&lt;/code&gt; element.
&lt;/audio&gt;&lt;/p&gt;
&lt;br&gt;
&lt;h3 id=&quot;transcript&quot;&gt;Transcript:&lt;/h3&gt;
&lt;p&gt;Let’s begin by finding a comfortable place to sit and write. Maybe you have your notebook open to a blank page, pen in hand. Maybe you have your computer opened to a fresh document in your text editor, and you’ve turned off potential distractions.&lt;/p&gt;
&lt;p&gt;Sit for a minute and take a deep breath. Notice your surroundings; notice how you are supported right now. Choose one thing you are especially grateful for in this moment. Maybe you have a few minutes to yourself in an otherwise chaotic day. Maybe you are enjoying the freshness of a new page or the fragrance of springtime. Whatever it is, hold it in your mind for a moment of appreciation. Close your eyes if it helps you focus.&lt;/p&gt;
&lt;p&gt;If you’re finding it difficult to find one thing to appreciate right now, whether it is because your mind is jumpy or your day has felt especially bleak, it’s okay. Take a few deep breaths and feel the air fill your lungs.&lt;/p&gt;
&lt;p&gt;Today I want to lead you through an exercise in groundedness. Groundedness is a quality of knowing where you stand, and that the ground is solid beneath your feet. It can be hard to stay grounded during a time when everything is changing and nothing is certain. But groundedness does not depend on your circumstances. You can find a place of groundedness, no matter what is happening around you.&lt;/p&gt;
&lt;p&gt;While it’s difficult to describe groundedness concretely, we can find clues of its presence in moments of calm, confidence, and quiet strength. Think about moments when you have felt those qualities. What helps you experience groundedness? What gives you a sense of calm, confidence, and quiet strength? Take the next few minutes to free-write about it. I’ll be back to check in soon.&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;How’s it going? If you need more time, feel free to press pause and continue writing. Whenever you’re ready, we’re going to take a break from words and focus instead on the language of image. Sometimes a particular image can give us perspective that helps us quickly return to a place of groundedness. Consider this poem by Rainier Maria Rilke, translated by Robert Bly, and the way he uses the image of music to ground us.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;My life is not this steeply sloping hour,&lt;/em&gt;&lt;br&gt;
&lt;em&gt;in which you see me hurrying.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Much stands behind me; I stand before it like a tree;&lt;/em&gt;&lt;br&gt;
&lt;em&gt;I am only one of my many mouths&lt;/em&gt;&lt;br&gt;
&lt;em&gt;and at that, the one that will be still the soonest.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;I am the rest between two notes,&lt;/em&gt;&lt;br&gt;
&lt;em&gt;which are somehow always in discord&lt;/em&gt;&lt;br&gt;
&lt;em&gt;because death’s note wants to climb over—&lt;/em&gt;&lt;br&gt;
&lt;em&gt;but in the dark interval, reconciled,&lt;/em&gt;&lt;br&gt;
&lt;em&gt;they stay there trembling.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;&lt;span class=&quot;spacer&quot;&gt;&lt;/span&gt;And the song goes on, beautiful.&lt;/em&gt;  &lt;/p&gt;
&lt;p&gt;Now let’s explore what your own image for groundedness might be. Close your eyes and breathe deep. When you think about the things that make you feel calm, confident, and full of quiet strength, what images or ideas come up for you? Let your imagination wander. &lt;/p&gt;
&lt;p&gt;Don’t worry if the images coming up for you feel silly or irrelevant or cliche. No matter what image your imagination comes up with, you can learn from it. Just keep letting your mind wander until you land on an image that resonates with you. If you’re having trouble thinking visually, think about ideas or phrases instead.&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;Have you landed on something yet? If you’re having trouble, feel free to use Rilke’s image of music, or you can borrow mine as a starting point. My image is a cozy house in a field full of orange and red poppies.&lt;/p&gt;
&lt;p&gt;Once you have your image, take a few minutes to write about it — what is this image? What might it have to teach you about what groundedness means for you?&lt;/p&gt;
&lt;p&gt;In the example of my cozy house in the poppy field, to me this is a symbol of the place I’m leading from when I’m at my best. In this house, I can be fully myself, surrounded by things that move me, reading books and writing and gardening and making delicious food. Beside my little house is a shed. It is where I store all of the “shoulds” that others wisely suggest, or that I put on myself. I can look at them in all their beauty and perfection, but return to my house and my garden as the place that holds the truth my decisions need to spring from.&lt;/p&gt;
&lt;p&gt;Take a few deep breaths as you hold your own image in your imagination. What is this image, and what can it teach you about groundedness? I’ll be back in a few minutes to check in.&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;How was that? It may have come swiftly or it may have been challenging. You may now have an image you can bring to mind when you need to ground yourself, or you may want to keep exploring it. Either outcome is normal.&lt;/p&gt;
&lt;p&gt;Whatever the case, when we make decisions from a place of groundedness, we allow ourselves to lead with calm, confidence and quiet strength. This is good not only for us and our own well-being, but is a contribution to everyone around us.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Check out the next Gather the Courage exercise: &lt;a href=&quot;/2020/05/06/flexibility/&quot;&gt;Flexibility&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Spaciousness]]></title><description><![CDATA[Dear friends,During the best of times, it’s hard to carve out time and mental space for big picture creative thinking. Right now, with fresh…]]></description><link>https://blog.andyet.com/2020/03/18/spaciousness/</link><guid isPermaLink="false">https://blog.andyet.com/2020/03/18/spaciousness/</guid><pubDate>Wed, 18 Mar 2020 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This exercise is part of a series originally shared on &lt;a href=&quot;https://gatherthecourage.com&quot;&gt;Gather the Courage&lt;/a&gt;, guided journaling for creative leaders to reflect, be encouraged, and make courageous decisions.&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Spaciousness&lt;/strong&gt; (You are here)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/06/groundedness/&apos;&gt;Groundedness&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2020/05/06/flexibility/&apos;&gt;Flexibility&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Dear friends,&lt;/p&gt;
&lt;p&gt;During the best of times, it’s hard to carve out time and mental space for big picture creative thinking. Right now, with fresh news of this global pandemic breaking every minute, it’s been even harder. (Why is it so hard to put down the phone when there are scary things happening?)&lt;/p&gt;
&lt;p&gt;Gather the Courage is meant to help you, as leaders, creators, and entrepreneurs of all stripes, make the space for the kind of thinking that will not only get us through this, but will make our world even better on the other side.&lt;/p&gt;
&lt;p&gt;Take care of yourself, and each other,&lt;/p&gt;
&lt;p&gt;Your friends at &amp;#x26;yet&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We’re starting small, with just one 12-minute exercise. Grab a notebook, a pen, and your headphones. You can use your laptop if distraction is not an issue for you.&lt;/p&gt;
&lt;p&gt;When you’re ready, press play.&lt;/p&gt;
&lt;p&gt;&lt;audio
  preload=&quot;metadata&quot;
  controls
  src=&quot;/guided-journaling-01-8c1d5b4fd9ee60ecc77ea47c80c191f9.mp3&quot;&gt;
Your browser does not support the
&lt;code&gt;audio&lt;/code&gt; element.
&lt;/audio&gt;&lt;/p&gt;
&lt;br&gt;
&lt;h3 id=&quot;transcript&quot;&gt;Transcript:&lt;/h3&gt;
&lt;p&gt;Let’s begin by settling into your space. Take a few deep breaths and find something to appreciate about the way you’re supported right now. Maybe you have a comfortable seat or a beautiful view. Maybe the sun is shining or you’ve got your favorite pen in your hand. Whatever it is, breathe deeply as you take a moment to appreciate it.&lt;/p&gt;
&lt;p&gt;If you’re having a particularly tough day and are struggling to find something to appreciate, that’s okay. On days like that for me, it’s enough to know that I’m trying.&lt;/p&gt;
&lt;p&gt;Now that you’ve settled in, let’s set our purpose for this time you’ve set aside today. As I’m recording this, we’re all undergoing a massive shift as we figure out how to respond to the COVID-19 pandemic. As a leader, this is impacting you in a unique way. Plans you may have been working on for months may seem irrelevant now. Your entire industry may be disrupted. You may be trying to determine what the right course of action is, even though you can’t know what will happen in the coming days, weeks, and months.&lt;/p&gt;
&lt;p&gt;It may feel urgent to figure out all the answers right now. But for today, my intention is to walk you through an exercise in spaciousness. For me, spaciousness is the feeling that I have all the time I need to do what needs to be done, no matter what is going on around me.&lt;/p&gt;
&lt;p&gt;What does spaciousness look like for you? Is it a feeling that no one is rushing you? Is it a feeling that no one expects anything from you right this minute? As you think about what spaciousness looks like for you, write down whatever comes to mind, even if it’s “I have no idea.”&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;As you’re writing, let’s start to think about ways you might be able to give yourself that spaciousness. Maybe you can manage other people’s expectations. Maybe you need to cancel some meetings to give yourself uninterrupted time. Maybe you need to take off the pressure entirely and take a day off, or even a few hours. How might you give yourself spaciousness? Or if you don’t know, write about why it’s hard for you. I’ll be back in a few minutes to check in.&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;If that was more challenging, it’s okay. It’s all learning. In fact, our feelings can be important clues to what we need. For the last few minutes of our time together, think about what you’re feeling around this concept. Is there a particular idea that excites you? Does some part of you feel resistant to the idea of spaciousness? What might those feelings be telling you? Take just a few minutes to write it down.&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;How’s it going? You may still be writing, and if that’s the case, feel free to hit pause and come back when you’re ready. If you’re finished, I want to encourage you to take this idea of spaciousness with you today as you’re thinking through possibilities and making decisions. Do what you can to give yourself what you need to feel like you have the time and space necessary to do what needs to be done.&lt;/p&gt;
&lt;p&gt;Spaciousness is a quality that brings down anxiety levels, not just in you, but in everyone around you. In that way, you giving yourself spaciousness is a gift to all of us.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Check out the next Gather the Courage exercise: &lt;a href=&quot;/2020/05/06/groundedness/&quot;&gt;Groundedness&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Last Bite]]></title><description><![CDATA[We think and talk a lot about building and strengthening relationships with customers. The conversations tend to focus on first impressions…]]></description><link>https://blog.andyet.com/2019/09/12/the-last-bite/</link><guid isPermaLink="false">https://blog.andyet.com/2019/09/12/the-last-bite/</guid><pubDate>Thu, 12 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We think and talk a lot about building and strengthening relationships with customers. The conversations tend to focus on first impressions, on-boarding, maintenance, and growth. It’s less common to hear about the process of ending a relationship. It can be uncomfortable to think about.&lt;/p&gt;
&lt;p&gt;What should you do when a client or customer is ready to say goodbye? Or maybe it’s you who is ready to move on. As hard as it can be to acknowledge this interaction as another part of the relationship, what happens here is so important.&lt;/p&gt;
&lt;p&gt;How can you make this experience of saying farewell as special and generous as you try to make all your other customer experiences?&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5d6734ddbecbdfeed398a70158739c3e/5dded/last-bite-eric.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 52.317880794701985%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsSAAALEgHS3X78AAABTElEQVQoz41SXW+CQBD0//+Mpi9tX/oD2sRa06Q0AkUJaKg1VgROPuS4AwoHdk4MMfXFCRx3uzPs3GYHbduKphFClGVZ4yMaHIHDBdozgIB1gOjjw93baLhwnIWzdJar9c/me7VOkj3Z7cIwjI4ghFRV1f8I0qYTj0YvpmlWdZ0dEcVJnueMcbKL0pRyzsMoppTWdf3PyADv0a2AoPfWp7uNuLhFR5OV729vhs9Pa9fb06yqxeEKdNeW4tfx2LItxvOUUjxxHDOY5jzLWOc/TVNsZIQx+Ef21DAYtizbmE5npvlpGJOJqmm6MZ0hoqqajKiaonwYhmHZkgayruuu66KqFNvz+buiOM4XuhoEATocEIJGe56/cd2tJ+H7fpIkfoAM2W5xDGRlGPD8AFyQKty4aQ/X4SQuyl9eFEVZUcbRM8xJPwnnOB+Pbv0D0K83M4nSjRYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Tweets by @ericzanol on Sept 4: “Don’t penalize people for cancelling their subscription. Make the cancellation process a positive one, don’t burn bridges. Customers are increasingly likely to come and go over time.”&quot;
        title=&quot;&quot;
        src=&quot;/static/5d6734ddbecbdfeed398a70158739c3e/90cbd/last-bite-eric.png&quot;
        srcset=&quot;/static/5d6734ddbecbdfeed398a70158739c3e/29fe9/last-bite-eric.png 151w,
/static/5d6734ddbecbdfeed398a70158739c3e/6728c/last-bite-eric.png 303w,
/static/5d6734ddbecbdfeed398a70158739c3e/90cbd/last-bite-eric.png 605w,
/static/5d6734ddbecbdfeed398a70158739c3e/a2b88/last-bite-eric.png 908w,
/static/5d6734ddbecbdfeed398a70158739c3e/a3767/last-bite-eric.png 1210w,
/static/5d6734ddbecbdfeed398a70158739c3e/5dded/last-bite-eric.png 1588w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some companies make it &lt;em&gt;painful&lt;/em&gt; to part ways. It feels like “good riddance” rather than “thanks for the memories.”&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;I’ve been known to demonstrate some… idiosyncrasies when I’m eating a meal (especially at restaurants). When the food arrives, I’ll lean my face in real close. I let the steam and smells drift into my nostrils. I inhale real deep. It’s the first moment of the meal I want to capture, savor. A chef cliche says people eat with their eyes first. But really, it’s the nose. Smell is hard-wired to the gut and the soul, setting us up for what comes next.&lt;/p&gt;
&lt;p&gt;The first bite. A first taste impression. A friendly (or hostile) hello. Our experience now has something to hold on to, to compare to our expectations. The food right now is at its most ideal temperature and presentation. Some meals have a first bite worth writing home about: a magical taste explosion; the second bite is eager. But for other meals, the second bite can be reluctant. Or maybe curious: does it get better? Some get no second bite at all. An often unfair resolution perhaps, especially for foods that really sing as you become more closely acquainted.&lt;/p&gt;
&lt;p&gt;After many bites comes my next meal moment, when the food and I are starting to understand one another. The perfect bite. Can all the ingredients and tastes be layered on the fork just so to capture the meal’s full depth and essence? Can we align and collaborate with purpose to create this one, perfect bite? Sometimes the meal is so balanced, several subsequent perfect bites are possible. Does a high percentage of perfect bites make a truly perfect meal?&lt;/p&gt;
&lt;p&gt;Even after this perfect bite (or several), comes my favorite and most important meal moment. The last bite. By this point the meal has nothing left to prove. We’re saying farewell. But the last bite can sometimes be even better than all the bites that came before. It will be different, of course. A meal changes during the time it takes us to eat it. But this last bite is a finishing touch. Look at all we experienced together and how soon is it until we can do this again?&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;I called the experience of saying goodbye “ending” a relationship, but as Eric mentions in the tweet above, leaving is often temporary. And even if it is permanent, that relationship happened and the feelings it created will continue to exist. And this final interaction will certainly linger.&lt;/p&gt;
&lt;p&gt;How can you shift what you’re doing to make your goodbyes as exciting and warm as your hellos?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Announcing our new cold read assessment]]></title><description><![CDATA[If you haven’t heard yet, we’ve recently started publicly offering a new assessment based on feedback from our clients and readers. As I…]]></description><link>https://blog.andyet.com/2019/08/07/announcing-cold-read-assessment/</link><guid isPermaLink="false">https://blog.andyet.com/2019/08/07/announcing-cold-read-assessment/</guid><pubDate>Wed, 07 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you haven’t heard yet, we’ve recently started publicly offering &lt;a href=&quot;https://andyet.com/services&quot;&gt;a new assessment&lt;/a&gt; based on feedback from our clients and readers. &lt;/p&gt;
&lt;p&gt;As I mentioned in our newsletter on &lt;a href=&quot;http://eepurl.com/gw2Ppz&quot;&gt;looking for that first tiny sign&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s funny that the service we’ve actually been selling isn’t even one we have on our website…
The reason this is so funny to me is that the process of selling a new offering always seems to happen this way. We launch with something we think is going to be the right solution, but when we get to talking to folks, the needs are different and we adjust. We learn way faster than we can implement. Sometimes it takes a while for the website to catch up.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, our website has caught up, though we’ve already been using a new approach to help our clients get clear on objectives, key results, and priorities that I’m noticing needs to be added. (Which I wrote about in last week’s newsletter on &lt;a href=&quot;http://eepurl.com/gyXgVT&quot;&gt;goal-setting and stewardship&lt;/a&gt;. Seriously, you should probably just subscribe to our newsletter to know what’s actually going on lol.)&lt;/p&gt;
&lt;p&gt;So &lt;a href=&quot;https://andyet.com/services&quot;&gt;check out our cold read assessment&lt;/a&gt; and tell us what you think. &lt;/p&gt;
&lt;p&gt;We’d love to see if we’re a good fit for your project, or to hear any thoughts, questions, or feedback. Just shoot me a quick email at &lt;a href=&quot;mailto:sarah@andyet.com&quot;&gt;sarah@andyet.com&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Transitioning to CEO and sharing as we go]]></title><description><![CDATA[I was a guest speaker for a program that a friend was facilitating last week, and she asked me what motivated me to write the first version…]]></description><link>https://blog.andyet.com/2019/07/15/transitioning-to-ceo/</link><guid isPermaLink="false">https://blog.andyet.com/2019/07/15/transitioning-to-ceo/</guid><pubDate>Mon, 15 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was a guest speaker for a program that a friend was facilitating last week, and she asked me what motivated me to write the first version of &lt;a href=&quot;https://gatherthepeople.com&quot;&gt;Gather the People&lt;/a&gt; (what was it, 5 years ago now?). I started telling the story of getting laid off from &amp;#x26;yet and having 60 days until the money ran out, and suddenly it hit me how surreal it is to be CEO of the company I was previously laid off from. Sure, it had occurred to me, but it hadn’t really sunk in until talking about it with someone who was looking at it from the outside.&lt;/p&gt;
&lt;p&gt;From the inside, it makes sense. Before &amp;#x26;yet, I was founder and CEO of a strategic web firm for over a decade. During my tenure at &amp;#x26;yet, we’ve needed a more predictable sustainable pipeline, but it has been so hard to shift a team skilled in solving a variety of hard problems into one committed to solving a more specific one. We’ve tried a few different directions over the years, sometimes giving in to being extremely veteran generalists, other times testing the waters in a specific direction. But it felt impossible to find the one thing that was a common denominator for the whole team.&lt;/p&gt;
&lt;p&gt;Last fall, we started doing this magical thing called “annual planning.” (I’m being intentionally facetious because we’ve historically avoided anything that faintly smells of hierarchical management, though good folks like Sally Mohr and Mark Brault have pushed for planning more intentionally in the past.)&lt;/p&gt;
&lt;p&gt;Anyway, through that process, we were able to see just how many competing priorities we had as an organization, and that we needed to stop testing the waters and actually commit to one specific direction. We took stock of our resources, including our past wins, our strengths as a team and as individuals, the problems we cared about and were interested in solving, and most especially how we could best help our clients grow and get to where they want to go. We worked with a consultant to add some objectivity to the mix and ultimately decided to focus on building strong customer relationships through creative technology.&lt;/p&gt;
&lt;p&gt;Our new direction is based on a framework that, through my past client work and the work we&apos;ve done at &amp;#x26;yet, we’ve used with over 100 clients to help them grow in a more effective, more intentional way. (In fact, if you sign up for our mailing list, we’ll share it with you.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.andyet.com/2019/04/09/thanks-for-this-bag-of-trash/&quot;&gt;We announced our new focus&lt;/a&gt; early April, and since then have been sharing our philosophies and strategies for growth. But mostly, we’ve been listening and learning, having conversations with folks who are trying to find sincere, creative, sustainable, scalable ways to grow their customer base.&lt;/p&gt;
&lt;p&gt;Many of the problems we’ve been talking about are ones businesses never get to stop solving—things change so quickly, especially online, that the need for constant learning and creative adaptability is always there.&lt;/p&gt;
&lt;p&gt;One of the ways I’ve historically worked through those challenges for myself is by sharing them openly with others. While our blog feels a little too open for me, I’ve started sharing our experiences and discoveries as we’re solving these problems on our mailing list. You can sign up at the bottom of this post.&lt;/p&gt;
&lt;p&gt;Thank you to all the folks who’ve been supportive of us as we’ve made these transitions. We’re really grateful, and we look forward to sharing everything we know to support your continued growth.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Ch-ch-ch-changes: The formation of Talky, inc. and a new CEO for &yet]]></title><description><![CDATA[We’re making a change in our organization and roles that I’m really excited about.&yet is spinning off Talky, inc. as its own company, with…]]></description><link>https://blog.andyet.com/2019/07/02/role-transitions/</link><guid isPermaLink="false">https://blog.andyet.com/2019/07/02/role-transitions/</guid><pubDate>Tue, 02 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’re making a change in our organization and roles that I’m really excited about.&lt;/p&gt;
&lt;p&gt;&amp;#x26;yet is spinning off Talky, inc. as its own company, with &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt; and &lt;a href=&quot;https://simplewebrtc.com&quot;&gt;SimpleWebRTC&lt;/a&gt; as its products. &lt;/p&gt;
&lt;p&gt;Ben Zemel will become CEO of Talky, inc. Lance Stout and Heather Young both have put considerable technical effort into building, maintaining and supporting SimpleWebRTC and they will join Ben as technical cofounders of the new company, with Lance as founding CTO. It has a been a privilege to work with all three of them as well as the many current and past contributors to getting SimpleWebRTC to this point, including Henrik Joreteg, Philip Roberts, Jon Hjelle, Amy Lynn Taylor, Diana Perkins, Lynn Fisher, Terry Carter, Elliott McNary, Luke Karrys, Dylan Staley, Jenna Tormanen, Jaime Robles, Audi Long, Kate Farrar, Nathan Fritz, Gar, Marcus Stong, NLF, Karolina Szczur, Sally Mohr, Chris Koehncke, Bear, Adam Baldwin, Jenn Turner, Isaac Lewis, Aaron McCall, Peter Saint-Andre, Xander Dumaine, and Philipp “Fippo” Hancke. It has taken a village, to put it lightly. Exceptional people, one and all.&lt;/p&gt;
&lt;p&gt;I’m really excited for the coming year in watching the continuation of the growth that the SimpleWebRTC team and product have experienced since launching paid signups earlier this year.&lt;/p&gt;
&lt;p&gt;At the same time, &amp;#x26;yet has been in the process of transitioning to a newer, more focused set of offerings, thanks to work that Sarah and Lynn have done over the past 9 months.&lt;/p&gt;
&lt;p&gt;As a natural part of that evolution, Sarah will become CEO of &amp;#x26;yet. This is something we’ve been talking about for a few months now and how we’ve been operating for a few weeks.&lt;/p&gt;
&lt;p&gt;&amp;#x26;yet, LLC operates with a board—not of partners but stewards—folks who have the responsibility for stewardship of the company. I’ve been the de-facto chair of the stewards board and I’ll stay in that role.&lt;/p&gt;
&lt;p&gt;Sarah has pretty awesome qualifications for taking on the role of CEO. For one thing, she’s already been leading the effort around &amp;#x26;yet’s focused offerings for months. But beyond that, she has actually been an entrepreneur and business owner longer than I have, including experience leading an agency where people truly loved to work.&lt;/p&gt;
&lt;p&gt;She is absolutely the right person to lead the company right now. She’s one of the most inspiring people I’ve ever known and I am seriously beyond excited to see where she takes &amp;#x26;yet.&lt;/p&gt;
&lt;p&gt;But I have another thing that I’m really excited about with all of this. I do intend to remain involved in both &amp;#x26;yet and Talky, Inc., but will be reducing my time in both so that I can put some additional time into another project.&lt;/p&gt;
&lt;p&gt;6 months ago, Sarah and I purchased a tiny community publication called &lt;a href=&quot;https://tumbleweird.org&quot;&gt;Tumbleweird&lt;/a&gt;, which a couple friends started a few years ago. Think of it as the Tri-Cities’ answer to The Stranger. Since December, I’ve slowly been working on making it more sustainable, teaming up with our Editor in Chief, Sara Quinn, and Managing Editor, Brendan Quinn, plus former owners Henry Hopscotch, Logan Kaufman, and Ted Miller. I’ve even gotten to collaborate a bit with former colleague NLF on some Tumbleweird-releated stuff which has been awesome.&lt;/p&gt;
&lt;p&gt;I am excited about the meaningful role Tumbleweird could play in our local community and culture, and very interested in its long-term potential. I’m going to begin putting more intentional time into helping it grow and flourish.&lt;/p&gt;
&lt;p&gt;I have faith in Sarah’s ability to lead &amp;#x26;yet, and confidence that &amp;#x26;yet is well positioned for success with such a strong leadership team in place.&lt;/p&gt;
&lt;p&gt;Eric and Sarah have demonstrated themselves a tremendous combo over the past year in creating and iterating the strategic planning processes that have helped us learn so much as an organization. From creative and cultural, Lynn is a dream to work with and so wise, unending in insight, ideas, and ways to make things better. No doubt, we’ll all be thrilled to have Terry back from maternity leave in late summer, too. She’s contributed so much to the way our team works. And, I mean, it always helps that we have one of the most experienced and knowledgeable CFOs we could ask for.&lt;/p&gt;
&lt;p&gt;I’ve seen the way our team’s leadership has worked together through challenges and opportunities. We’ve learned and grown a lot over the years. I believe strongly in the processes, rhythms, candor, and supportive culture we’ve developed.&lt;/p&gt;
&lt;p&gt;And I definitely believe in the people.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The value of an outside perspective]]></title><description><![CDATA[I don’t think I need to convince anyone that having another person review your work is a good thing. It’s probably already built into your…]]></description><link>https://blog.andyet.com/2019/06/19/the-value-of-an-outside-perspective/</link><guid isPermaLink="false">https://blog.andyet.com/2019/06/19/the-value-of-an-outside-perspective/</guid><pubDate>Wed, 19 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/828f2b24479a89acaad6c877261670d2/914ae/blog-illo-outside-perspective.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 60.9271523178808%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsSAAALEgHS3X78AAABqElEQVQozz1SXW+UQBTlP/sLfPJH+OSTz9XoU43xoU02tjG2NbqpwiyU2flkWKA7s8CCBy7lhAzD5dx77ldUlqXWuigK+4Jsxm63w5mm6XoxxuAvMXF3zkV0OxwOsCqlEIvYUsopqLXO2j3nMIINAmjgkExEbgAFg4lzXtfVOA6nEKQpEqGyvRD7PWKBQMoUIiIfM4OsTdN0/XgeRqXNXSriKmyY2LKsKsuZYtcyI1KjkKVzSMT79ly87/2/m0f+M8k+fLu+ZfwHtwe3YK08groQgsQRMgTfdUPbPLRePqTq89Xm1es3bz9e3uRFF7zWS3bkMtWMF/UAF+9909RV3frQKim+/Irffd1c3MdXf5KyqkGDJ/HhOClTJlQzTO2EU993t9u/96r6/TyypkvqwNCcuVkksyiTG7LRxqBb44xnHy63WWKc7Uc7jLGruZ78aC4ocOo2JYwPEj8ej33fwzkV6tP3u20uxeksT0Na+1xpN/cJ08Y5OdOcy2kMy5zRDClE9vQUJyzL81wIetTLnAmLMk2fggGMMewT9jHFVu4WwLju1rpR/wFMe5QxGkUDNQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Outside a window, a yeti smiles and waves hello.&quot;
        title=&quot;&quot;
        src=&quot;/static/828f2b24479a89acaad6c877261670d2/90cbd/blog-illo-outside-perspective.png&quot;
        srcset=&quot;/static/828f2b24479a89acaad6c877261670d2/29fe9/blog-illo-outside-perspective.png 151w,
/static/828f2b24479a89acaad6c877261670d2/6728c/blog-illo-outside-perspective.png 303w,
/static/828f2b24479a89acaad6c877261670d2/90cbd/blog-illo-outside-perspective.png 605w,
/static/828f2b24479a89acaad6c877261670d2/914ae/blog-illo-outside-perspective.png 860w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;When is someone on the outside very helpful (and not creepy)?&lt;/figcaption&gt;
&lt;p&gt;I don’t think I need to convince anyone that having another person review your work is a good thing. It’s probably already built into your teams and processes. Programmers pair up and build a feature together, bouncing ideas off one another. Code reviews are required before new work can be merged into our apps. Design teams hold critiques where the work is examined and people provide feedback.&lt;/p&gt;
&lt;p&gt;In most of these cases, the people reviewing the work are our teammates or clients. Let’s say they’re “People who get you.”&lt;/p&gt;
&lt;h2 id=&quot;people-who-get-you&quot;&gt;&lt;a href=&quot;#people-who-get-you&quot; aria-label=&quot;people who get you permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;People who get you&lt;/h2&gt;
&lt;p&gt;These people work with you. Sometimes it feels like your coworkers and clients understand you better than you do. This makes discussing your work super productive. They know what you’re trying to do, they get your communication style, and they see a similar vision for the work. When the feedback is good, it’s &lt;em&gt;really&lt;/em&gt; good. You’re collaborating and the work is flowing.&lt;/p&gt;
&lt;p&gt;But are there gaps that can cause the work to suffer? The People who get you are usually like-minded and can be oblivious or ignorant to the same things you are. Have you ever seen a product or marketing campaign that’s just blatantly offensive? You ask yourself, “&lt;em&gt;How&lt;/em&gt; could they not see it? No one said anything?” Maybe all the people in the room were missing this crucial information. Or the person who saw it couldn’t speak up or was ignored.&lt;/p&gt;
&lt;p&gt;Keeping feedback inside a project, team, or org can be weighed down by cultural baggage. Teams love to say they’re low on politics, but honestly it’s unavoidable. A higher-up can drop a bomb of feedback and derail a team. Teammates can resist solutions because it’s not how it’s always been done. Sometimes feedback and ideas are &lt;em&gt;actually heard&lt;/em&gt; from only specific people or roles, despite how many people are saying them.&lt;/p&gt;
&lt;p&gt;So what then? Ask for feedback from people who don’t know you? That can be risky. They don’t know your history, all the difficult decisions you’ve had to make to get to today. They don’t have an investment in your success. You’ll have to catch them up and answer questions you’ve answered before, turn down ideas you’ve already tried and rejected. It’ll take too much time.&lt;/p&gt;
&lt;p&gt;But there’s an opportunity there, with these People who don’t get you …yet.&lt;/p&gt;
&lt;h2 id=&quot;people-who-dont-get-you-yet&quot;&gt;&lt;a href=&quot;#people-who-dont-get-you-yet&quot; aria-label=&quot;people who dont get you yet permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;People who don’t get you …yet&lt;/h2&gt;
&lt;p&gt;The cool thing about getting an outside perspective is it’s a viewpoint that’s impossible for you to have yourself. Seeing things for the first time is insight a person has once.&lt;/p&gt;
&lt;p&gt;We’ve seen the immense value of putting our work and processes in front of a beginner or a brand new teammate and them asking questions and speaking their mind. It can immediately reveal gaps in documentation, process, or our assumptions. It brings a unique clarity that only a Person who doesn’t get you yet can.&lt;/p&gt;
&lt;p&gt;And the time spent “catching them up” is the perfect chance to evaluate how you explain your work. There &lt;em&gt;is&lt;/em&gt; only so much time, so what information do you convey and what do you cut? They’ll likely ask questions you’ve already answered, but I’m certain they’ll ask questions you haven’t considered. Often decisions get made without us realizing it and this forces you to examine them and explain why things are as they are.&lt;/p&gt;
&lt;p&gt;People who don’t get you yet can see and evaluate your work without the baggage I mentioned earlier. They can see the work at face value, as it is. They won’t be worried about shareholders or the many years you’ve spent iterating. Does the work reflect the purpose and direction you’re selling?&lt;/p&gt;
&lt;p&gt;And as far as investing in your success, if you find the right People who don’t get you yet, they will approach this important job of giving feedback with support and encouragement in mind. It can absolutely be counterproductive to seek this valuable insight from people who don’t have your back. In our experience, peers and/or consultants who can bring humility, kindness, and expertise to this process are value multipliers.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We’ve been on both sides of this, as clients and consultants, and it’s amazing the insights an outside perspective can bring. If you’d like another set of eyes on your work, definitely &lt;a href=&quot;https://andyet.com/contact&quot;&gt;reach out to us&lt;/a&gt;. &amp;#x3C;3&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Swag can be object-free]]></title><description><![CDATA[We’ve previously talked about corporate swag being broken. “Thanks for this bag of trash” is an absolutely fair response at a lot of…]]></description><link>https://blog.andyet.com/2019/06/04/swag-can-be-object-free/</link><guid isPermaLink="false">https://blog.andyet.com/2019/06/04/swag-can-be-object-free/</guid><pubDate>Tue, 04 Jun 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9cae333d46b1b27edc67e7dda589c87d/914ae/blog-swag-illo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 58.27814569536424%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsSAAALEgHS3X78AAABO0lEQVQozz3SWZLCMAwEUN//jmErhkAgBCZh/5kXdw2qwsjqbkmWUo7H4+VyGcex67rNZrNer4dhuFYD/Vbb7/fi0Ou/gUjKNE3EBMTn85kPiw925aB+ocPhgAzil8fj4U8KAvDn81GKo9rtduOnKefr9cKUhf75fJ5Op+LX970T2wmLACMFBfnOFITKFVVJ4sVisd1uAcnNOKC2bZumcWpNhD4Q5ixOG/SpIzRWC1U7XTVX1aRIAZCMxSUDv9/vNGnSIGRJh86pWiCDyDrmN7tIj5qxK+6axkR2u10W+W0kW8iLSkaCQb9cLlerVTbXVwNlq15uKIEyFE3N4rxESz/VhmqCgbI2LYAyTs06bauElA8DL7tVSi69ySLoihAo0+XPbzYbJClEMXwk3w8w7IwN4f1+i8tFpqy8f7ATnpkWqjrzAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;T-shirts that say “Another men&apos;s cut t-shirt” and tote bags that say “Another canvas tote bag.”&quot;
        title=&quot;&quot;
        src=&quot;/static/9cae333d46b1b27edc67e7dda589c87d/90cbd/blog-swag-illo.png&quot;
        srcset=&quot;/static/9cae333d46b1b27edc67e7dda589c87d/29fe9/blog-swag-illo.png 151w,
/static/9cae333d46b1b27edc67e7dda589c87d/6728c/blog-swag-illo.png 303w,
/static/9cae333d46b1b27edc67e7dda589c87d/90cbd/blog-swag-illo.png 605w,
/static/9cae333d46b1b27edc67e7dda589c87d/914ae/blog-swag-illo.png 860w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We’ve previously talked about corporate swag being broken. &lt;a href=&quot;https://blog.andyet.com/2019/04/09/thanks-for-this-bag-of-trash/&quot;&gt;“Thanks for this bag of trash”&lt;/a&gt; is an absolutely fair response at a lot of conferences. You might be familiar with this sight: tables of tote bags filled with brochures and trinkets no one really wants.&lt;/p&gt;
&lt;p&gt;A better option is spending a bit more for actually &lt;em&gt;useful&lt;/em&gt; objects. The problem here though is even useful objects can create clutter. How many bottle openers, battery packs, and steel water bottles can one person really use? T-shirts can be useful, but not if they don’t fit properly and there definitely is such a thing as &lt;em&gt;too many&lt;/em&gt; shirts.&lt;/p&gt;
&lt;p&gt;We do understand it though. Conferences are a chance to get your company in front of people. It’s low-risk marketing, can help with brand recognition, and is a major recruiting opportunity. But dollar for dollar, how effective is it really? Do we even know? Unfortunately, swag can sometimes cause a &lt;em&gt;negative&lt;/em&gt; effect for your product (especially if it’s just more of the same stuff along with twenty &lt;em&gt;other&lt;/em&gt; companies’ swag).&lt;/p&gt;
&lt;p&gt;So maybe your money could be spent better. In our experience, people respond to things that feel special, personal. We’ve seen the positive ripple from creating swag that is personalized and meaningful: something attendees can cherish long after the conference ends and they head home.&lt;/p&gt;
&lt;p&gt;But this still too can create clutter. And sometimes sentimental objects create even more burden for us to hold on to them.&lt;/p&gt;
&lt;p&gt;The inimitable &lt;a href=&quot;https://twitter.com/fox/status/1113789815189901313&quot;&gt;Karolina Szczur recently tweeted&lt;/a&gt;, “Conference and company swag is environmental damage.” And she’s not wrong. At the scale many companies give away swag, it seems urgent we change our perspective on what swag can be.&lt;/p&gt;
&lt;h2 id=&quot;stuff-we-all-get&quot;&gt;&lt;a href=&quot;#stuff-we-all-get&quot; aria-label=&quot;stuff we all get permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Stuff we all get?&lt;/h2&gt;
&lt;p&gt;&lt;img class=&quot;img-narrow&quot; src=&quot;/blog-swag-michael-scott-d7a5e3dcab016a5693fc172aad18ba1f.gif&quot; alt=&quot;Michael Scott from The Office holds a bunch of bags and a foam finger and saysm &amp;#x201C;Swag! Stuff we all get.&amp;#x201D;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Does it need to be stuff? Could swag be object-free? Is that possible?&lt;/p&gt;
&lt;p&gt;If it still &lt;em&gt;must&lt;/em&gt; be physical objects, could swag be something with a tiny footprint that focuses on experience? Maybe you provide a snack with very light packaging, meant to be eaten that day. Or provide a gift card to a local coffee shop or restaurant nearby. “Take a friend out for lunch on us.” &lt;/p&gt;
&lt;p&gt;But if we truly went object-free, what could that look like? It’s not about stuff we collect and bring home, but about experiences and community betterment. Take the money (or more) you would have spent on swag and instead maybe:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sponsor a local musician to play at the event&lt;/li&gt;
&lt;li&gt;sponsor all-day child care for the event&lt;/li&gt;
&lt;li&gt;sponsor live captioning and interpreters&lt;/li&gt;
&lt;li&gt;purchase tickets for some attendees from under-represented groups&lt;/li&gt;
&lt;li&gt;hire a local photographer to take professional headshots for attendees during the event&lt;/li&gt;
&lt;li&gt;pay a few local designers and developers to provide portfolio or code reviews during the conference&lt;/li&gt;
&lt;li&gt;buy and plant a tree for each attendee&lt;/li&gt;
&lt;li&gt;donate the money to a non-profit and match attendee donations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The way you spend money matters and people want to support and work for companies that share their values. A company that makes child care or attendance for under-represented groups possible is using its money to open opportunities for those often left out. It disrupts the status quo, it makes a difference, and people will remember it.&lt;/p&gt;
&lt;p&gt;Spending conference and swag budgets differently would not only greatly benefit the attendees and the community, but the value is many times greater for the companies that take the chance. This generosity is long-lasting and much more impactful in building the relationships you want with your community and customers.&lt;/p&gt;
&lt;p&gt;So what do you think? Do you see companies and conferences already heading this direction? We’d love to hear your thoughts. &amp;#x3C;3&lt;/p&gt;
&lt;p&gt;P.S. We have a whole bunch more ideas about unique and object-free swag for your company. &lt;a href=&quot;https://andyet.com/contact&quot;&gt;Let’s chat.&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[A technical look at Facecamp]]></title><description><![CDATA[We recently released face.camp, a Progressive Web App (PWA) that allows you to take animated gifs of your face and share them with your fave…]]></description><link>https://blog.andyet.com/2019/05/31/a-technical-look-at-facecamp/</link><guid isPermaLink="false">https://blog.andyet.com/2019/05/31/a-technical-look-at-facecamp/</guid><pubDate>Fri, 31 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We recently &lt;a href=&quot;https://blog.andyet.com/2019/05/30/introducing-facecamp/&quot;&gt;released face.camp&lt;/a&gt;, a Progressive Web App (PWA) that allows you to take animated gifs of your face and share them with your fave Slack channel. We’ve also open sourced the code on &lt;a href=&quot;https://github.com/andyet/face.camp&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It was the first project I worked on when I (&lt;a href=&quot;https://blog.andyet.com/2019/02/06/sabbaticals-and-muscle-memory/&quot;&gt;also&lt;/a&gt;) came back from a three-month sabbatical. I had previously burned out on coding and I found myself for the first time getting excited about having the freedom to go down rabbit holes to solve even the smallest of problems. Most of these problems weren’t even practical to solve, but I had a good time solving them.&lt;/p&gt;
&lt;h2 id=&quot;preact&quot;&gt;&lt;a href=&quot;#preact&quot; aria-label=&quot;preact permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Preact&lt;/h2&gt;
&lt;p&gt;Knowing that the site was going to be a PWA, I wanted to keep the frameworks used as small as possible and take advantage of any tooling that would allow me to do that. &lt;a href=&quot;https://preactjs.com&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;preact&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/developit/preact-cli&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;preact-cli&lt;/code&gt;&lt;/a&gt; seemed like a perfect fit.&lt;/p&gt;
&lt;h2 id=&quot;browser-support-and-byte-shaving&quot;&gt;&lt;a href=&quot;#browser-support-and-byte-shaving&quot; aria-label=&quot;browser support and byte shaving permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Browser Support and Byte Shaving&lt;/h2&gt;
&lt;p&gt;face.camp uses the &lt;code class=&quot;language-text&quot;&gt;getUserMedia&lt;/code&gt; API which has been available for a while in &lt;a href=&quot;https://caniuse.com/#feat=stream&quot;&gt;most modern browsers&lt;/a&gt;. I took this list of browsers and updated them to include only some of the more recent versions of each so that the site would be able to ship newer JavaScript features supported by these browsers including &lt;code class=&quot;language-text&quot;&gt;Promise&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;const&lt;/code&gt;  &amp;#x26; &lt;code class=&quot;language-text&quot;&gt;let&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;fetch&lt;/code&gt;, and arrow functions (&lt;code class=&quot;language-text&quot;&gt;=&amp;gt;&lt;/code&gt;). The JavaScript for the site gets built via &lt;a href=&quot;https://github.com/developit/preact-cli&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;preact-cli&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/babel/babel/tree/master/packages/babel-preset-env&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;@babel/present-env&lt;/code&gt;&lt;/a&gt;, but I noticed that even when supplying the list of supported browsers there was still room to tweak the final build. So I went digging to see what else I could do.&lt;/p&gt;
&lt;p&gt;The first thing I wanted to do was found out how many bytes I was saving by shipping ES2015+. &lt;a href=&quot;https://github.com/andyet/face.camp/blob/master/scripts/build-sizes.js&quot;&gt;Using a script&lt;/a&gt; that would build multiple versions of the app with different build configurations, I found that by switching the supported browsers from the default of &lt;code class=&quot;language-text&quot;&gt;[&amp;#39;&amp;gt; 0.25%&amp;#39;, &amp;#39;IE &amp;gt;= 9&amp;#39;]&lt;/code&gt;, I saved 506 bytes. Armed with my slightly over-engineered script, I went out looking for what other configurations would save even the smallest amount.&lt;/p&gt;
&lt;p&gt;The next thing I found, is that I could also use native &lt;a href=&quot;https://caniuse.com/#feat=async-functions&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;async/await&lt;/code&gt;&lt;/a&gt; instead of the &lt;a href=&quot;https://github.com/MatAtBread/fast-async&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;fast-async&lt;/code&gt;&lt;/a&gt; plugin. This saved me 234 bytes! Sure that’s only a savings of 0.74% of the total bundle size, but…actually I don’t really have a justification for savings 234 bytes. Remember what I said above about doing things that weren’t practical?&lt;/p&gt;
&lt;p&gt;I also noticed that some of the babel plugins were using an inline helper to replace the object spread operator. Since the list of supported browsers for the project all supported &lt;code class=&quot;language-text&quot;&gt;Object.assign&lt;/code&gt;, I added &lt;code class=&quot;language-text&quot;&gt;useBuiltIns: true&lt;/code&gt; to the settings for each plugin. And yes, the savings were even smaller than before (93 bytes, but who’s counting).&lt;/p&gt;
&lt;p&gt;When I combined all those build settings I lost some of the aggregate savings, but still came in at 808 bytes smaller than when I started. If you’re as interested as me in shrinking a build by ~2.5%, you can check out the &lt;a href=&quot;https://gist.github.com/lukekarrys/008a936aaecbc7f663abdab7bc602ebd&quot;&gt;raw gist of the script’s output&lt;/a&gt; or &lt;a href=&quot;https://github.com/andyet/face.camp/blob/c8101becf8da88a0bffd36f48a0542540a77c475/package.json#L102&quot;&gt;try running it yourself&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;slack-max-inline-gif-size&quot;&gt;&lt;a href=&quot;#slack-max-inline-gif-size&quot; aria-label=&quot;slack max inline gif size permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Slack Max Inline Gif Size&lt;/h2&gt;
&lt;p&gt;One of our favorite parts about face.camp is how Slack is able to put the gifs inline into whichever channel or conversation you want. However, we found out that Slack will only do this for images less than 2MB in size. The site uses &lt;a href=&quot;https://jnordberg.github.io/gif.js/&quot;&gt;gif.js&lt;/a&gt; and a solution I learned from &lt;a href=&quot;https://github.com/latentflip/gifhu.gs&quot;&gt;Philip Roberts’ gifhu.gs&lt;/a&gt; to generate the gifs. But they would just often enough come out to greater than 2MB depending on the complexity of the image. I tried lowering the framerate, quality, and size, but found that in order to &lt;strong&gt;always&lt;/strong&gt; get the size lower than 2MB those options noticeable degraded the image quality for most other images.&lt;/p&gt;
&lt;p&gt;The easiest solution I found was to make the computer keep &lt;a href=&quot;https://github.com/andyet/face.camp/blob/c8101becf8da88a0bffd36f48a0542540a77c475/src/lib/gif.js#L80-L92&quot;&gt;re-rendering the gif until the size was under 2MB&lt;/a&gt;! It progressively lowers the size of the image and keeps track of the scaling multiplier so any future image in that session will use the new scale. Eagle-eyed users might notice that the progress meter sometimes runs twice, this is why!
&lt;a href=&quot;https://caniuse.com/#feat=async-functions&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;pwas-and-ios&quot;&gt;&lt;a href=&quot;#pwas-and-ios&quot; aria-label=&quot;pwas and ios permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;PWAs and iOS&lt;/h2&gt;
&lt;p&gt;In 2018, iOS 11.3 added support for Progressive Web Apps. However, one big part that was missing is support for &lt;code class=&quot;language-text&quot;&gt;getUserMedia&lt;/code&gt; inside those PWAs. Since I wanted to keep support for PWAs on Android, I didn’t want to drop support altogether. I ended up stumbling upon the open-source &lt;a href=&quot;https://github.com/nolanlawson/pinafore&quot;&gt;Pinafore&lt;/a&gt; project and finding an issue about another shortcoming in iOS PWAs that they had to work around. I ended up copying their solution, which is to use &lt;a href=&quot;https://github.com/nolanlawson/pinafore/pull/443&quot;&gt;user agent sniffing to remove the manifest.json &lt;code class=&quot;language-text&quot;&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;let-us-know-what-you-think&quot;&gt;&lt;a href=&quot;#let-us-know-what-you-think&quot; aria-label=&quot;let us know what you think permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let Us Know What You Think&lt;/h2&gt;
&lt;p&gt;The code is now &lt;a href=&quot;https://github.com/andyet/face.camp&quot;&gt;open source&lt;/a&gt; on GitHub. Please play around it with and let us know if you have any issues, questions, or enhancements by &lt;a href=&quot;https://github.com/andyet/face.camp/issues/new&quot;&gt;opening an issue&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing Facecamp: Chat your mug!]]></title><description><![CDATA[Hey friends with faces! We just launched a little app called Facecamp over at face.camp. With Facecamp you can share short, animated gifs of…]]></description><link>https://blog.andyet.com/2019/05/30/introducing-facecamp/</link><guid isPermaLink="false">https://blog.andyet.com/2019/05/30/introducing-facecamp/</guid><pubDate>Thu, 30 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/35c7b3a102cdc395f2065363113a69cc/5a190/facecamp-logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 50.331125827814574%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsSAAALEgHS3X78AAAA6ElEQVQoz42SyQ6CQAxA+f/P8WCMBxMPnjQx0bjcTEQBEQSVRWarLYtBtswkTYFpXl+HMaBjKaVgaA3tG83CqjjiCoJMtiLm6q+uCTe6OjOpYHzN8phaGUzKPDIzmDts0LQTmKDFLS1szFiAi8/nSOR724DD2ue90G6gUOAkxYj7kMMOIZSpwSWWsPI4HJ9FA6kDTBFoI/DFVG5GVguXQYgN/I+E01v8LLWAcTkyAQ9oRkZLrwBsHhxmNsuPRXtk6kpmNJ6FpnSGdwx6p+99f7gFrBcJzGRK41MmI8qyAdMy1L3Y9ftYrS9ygRGjwshsJgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;A logo of a camping mug with the FACECAMP on it.&quot;
        title=&quot;&quot;
        src=&quot;/static/35c7b3a102cdc395f2065363113a69cc/90cbd/facecamp-logo.png&quot;
        srcset=&quot;/static/35c7b3a102cdc395f2065363113a69cc/29fe9/facecamp-logo.png 151w,
/static/35c7b3a102cdc395f2065363113a69cc/6728c/facecamp-logo.png 303w,
/static/35c7b3a102cdc395f2065363113a69cc/90cbd/facecamp-logo.png 605w,
/static/35c7b3a102cdc395f2065363113a69cc/5a190/facecamp-logo.png 800w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hey friends with faces! We just launched a little app called Facecamp over at &lt;a href=&quot;https://face.camp/&quot;&gt;face.camp&lt;/a&gt;. With Facecamp you can share short, animated gifs of your face within your fave Slack channel.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/facecamp-image-preview-9f851d215f0ec25f09b26dc42f0756d3.gif&quot; alt=&quot;Slack chat with a looping gif of a woman smiling and waving.&quot;&gt;&lt;/p&gt;
&lt;p&gt;There’s not much to it. You sign in with Slack, capture a gif of your mug, add a message, and share directly into your org’s Slack. You can share to public or private channels and direct messages (if you choose to). You can sign into multiple Slack orgs too and swap between them (I know you have a bunch you belong to).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/facecamp-switch-teams-39e4f11b7ab7f4b2bc9af4d152e2f134.gif&quot; alt=&quot;The Facecamp UI and the mouse clicks on a shuffle button to switch between different teams.&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-for&quot;&gt;&lt;a href=&quot;#why-for&quot; aria-label=&quot;why for permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why for?&lt;/h2&gt;
&lt;p&gt;We have a remote team and sometimes we go too long without seeing each other’s faces. We use &lt;a href=&quot;https://face.camp/&quot;&gt;Facecamp&lt;/a&gt; to do a roll-call before our monthly all-hands, posting silly gifs of ourselves and answering ice breaker questions (btw, “How do you like your eggs?” is one of the very best). We wanted a way to see more of each other and feel connected and Facecamp makes that fun and easy.&lt;/p&gt;
&lt;p&gt;Capturing gif reactions isn’t a new idea (how great is &lt;a href=&quot;https://chat.meatspac.es/&quot;&gt;chat.meatspac.es&lt;/a&gt;? remember its &lt;a href=&quot;https://soledadpenades.com/posts/2013/meatspaces-decentralisation-and-miniapis/&quot;&gt;public debut at RealtimeConf&lt;/a&gt;? ahh, memories), but we wanted a way to make it as seamless as we could and where we were already gathered: in Slack.&lt;/p&gt;
&lt;p&gt;Building custom integrations for Slack has been a dream for us in streamlining our processes, improving communication, and bringing more fun to the workday. Facecamp definitely does.&lt;/p&gt;
&lt;h2 id=&quot;dig-deeper&quot;&gt;&lt;a href=&quot;#dig-deeper&quot; aria-label=&quot;dig deeper permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dig deeper&lt;/h2&gt;
&lt;p&gt;Curious how Facecamp works? It’s &lt;a href=&quot;https://github.com/andyet/face.camp/&quot;&gt;open source on GitHub&lt;/a&gt; where you can look behind the scenes. Huge shoutout to &lt;a href=&quot;https://twitter.com/philip_roberts&quot;&gt;Philip Roberts&lt;/a&gt;, whose work made a lot of this app possible. &lt;a href=&quot;https://andyet.com/team/luke&quot;&gt;Luke Karrys&lt;/a&gt; will be posting a technical look at the app soon, so stay tuned!&lt;/p&gt;
&lt;h2 id=&quot;make-facecamp-better&quot;&gt;&lt;a href=&quot;#make-facecamp-better&quot; aria-label=&quot;make facecamp better permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Make Facecamp better&lt;/h2&gt;
&lt;p&gt;Find a bug with Facecamp or have an idea to make it better? We’d love for you to &lt;a href=&quot;https://github.com/andyet/face.camp/issues&quot;&gt;file an issue on GitHub&lt;/a&gt;. Or if GitHub isn’t your thing, tweet at us at &lt;a href=&quot;https://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt;. Let us know what you think of it! And show us your mug!&lt;/p&gt;
&lt;p&gt;P.S. We value your privacy and we don’t gather, store, or sell any of your data. None of your data runs through our servers. Read the full &lt;a href=&quot;https://face.camp/privacy&quot;&gt;privacy policy&lt;/a&gt; for more info.&lt;/p&gt;
&lt;p&gt;P.P.S. We love using creative technology to connect on a personal level. We’d love to help your company connect and strengthen relationships with your customers. &lt;a href=&quot;https://andyet.com/contact&quot;&gt;Reach out!&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Project Meh-nagement]]></title><description><![CDATA[How to be unopinionated about process, but still keep things on track.Lately I’ve settled into a role where I act as project manager on a…]]></description><link>https://blog.andyet.com/2019/05/28/project-meh-nagement/</link><guid isPermaLink="false">https://blog.andyet.com/2019/05/28/project-meh-nagement/</guid><pubDate>Tue, 28 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;how-to-be-unopinionated-about-process-but-still-keep-things-on-track&quot;&gt;&lt;a href=&quot;#how-to-be-unopinionated-about-process-but-still-keep-things-on-track&quot; aria-label=&quot;how to be unopinionated about process but still keep things on track permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to be unopinionated about process, but still keep things on track.&lt;/h2&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0dbf584cc0351e51ed9b7275696728b2/1cfc2/blog-illo-project-management.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 58.27814569536424%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsSAAALEgHS3X78AAACRklEQVQoz2P4jxf8+/cPTP3/+/LT3x+/0GQZgPj1y5fXblz//PnL+48fgejVmzfff/z49v3Ht2/fgQio9fyNp4uUG8/5Tvvx7zfELITmzfsO+WWXfvny5fP7d+9fv7x66eKrFy/+//3359evp0+evHx4N3fhZpaEloKI5v8/fv6DOweieeX2PRYxmW9evzYLipFzDdL0jYgqrT167uLkpav1A6N1A6KV3AIE7Tzm7NgJVPz3718UzYs2breKyXj18uWybbtb5y9jMXZl0Hdk0Hdg0LZlMHBiNHJh0HfhtXC/e+cOUPH79+9RNK/fc2D28rUQ/pUbt0QcAxjMXXw14qx0Ihms3NmtfMTsvQ2CYm7dvffv79+3b9/+/PkTofnTx4/vvn169vmNc2ExuyXQWicGK48ElaR41WQGM2cGNXOZot7V1x5/e//29Zu37969e/r0KVTz79+/X7x88Xbv1TfLT/XEtPWUTHXNKWPQtGEz9mDQdZX2jpq/fvPGm8/Pvvz0/9/fX79BoQ20HOJyBiAB1D9j1sHy+u0bph/6f/v9pGWrZF2DNPyiRO2956/dCFT05+/f33/+AC38+vUrUPHr16+hmoH4548fh2/d2nXnztF7t958/fDgwYPPHz9MmTihrqry+rXrXz68n3H2/s5bT7+8e/P123eg5levXiE0A1l/f/z4//Pn3x8/v37+8ufPnzdv3i5dtmzuvHnnz58HKtj36P2pR6+/ffoA8vG7d8AARwQYJM38Q0qSQOMh0YEcq5gAABgfNI1DMEKDAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;A desktop computer surrounded by various apps, talk bubbles, and arrows.&quot;
        title=&quot;&quot;
        src=&quot;/static/0dbf584cc0351e51ed9b7275696728b2/90cbd/blog-illo-project-management.png&quot;
        srcset=&quot;/static/0dbf584cc0351e51ed9b7275696728b2/29fe9/blog-illo-project-management.png 151w,
/static/0dbf584cc0351e51ed9b7275696728b2/6728c/blog-illo-project-management.png 303w,
/static/0dbf584cc0351e51ed9b7275696728b2/90cbd/blog-illo-project-management.png 605w,
/static/0dbf584cc0351e51ed9b7275696728b2/1cfc2/blog-illo-project-management.png 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Lately I’ve settled into a role where I act as project manager on a regular basis. This role kind of evolved organically, and I didn’t come into it with a formal project management background, but rather a design background. To me, project management just feels like another creative problem to solve.&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet we tend to work on projects that are outside of the box, both creatively and technically. Whether this be &lt;a href=&quot;https://www.simplewebrtc.com/&quot;&gt;internal projects&lt;/a&gt; or &lt;a href=&quot;https://andyet.com/services&quot;&gt;consulting&lt;/a&gt; work, each project has different goals, unique contributors, scope, constraints - you name it. Because of this, there’s really no one-size-fits-all project management process that works for every project. I tend to reinvent the wheel (er, ‘process’) with every project. Sure, there are some basic approaches that I’ve noticed work really well, but I still see every project as an opportunity to evolve and iterate on project management as a practice.&lt;/p&gt;
&lt;p&gt;I generally start by asking myself the same fundamental questions:&lt;/p&gt;
&lt;h2 id=&quot;start-with-the-basics&quot;&gt;&lt;a href=&quot;#start-with-the-basics&quot; aria-label=&quot;start with the basics permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Start with the basics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Goals:&lt;/strong&gt; It’s helpful to take stock of the over-arching project goals. This may seem obvious but it can be easy to lose sight of bigger picture goals when solving more granular problems, or even to forget to establish clear metrics for success in the first place.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What are the external goals of the project?&lt;/li&gt;
&lt;li&gt;What are the internal goals of the project?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt; If there’s anything that can make a project feel like a win-win for yourself and the client, it&apos;s setting clear requirements. This ensures that client expectations are met and that scope creep doesn’t threaten planned profit.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is the project scope?&lt;/li&gt;
&lt;li&gt;Is everyone involved aware of the scope?&lt;/li&gt;
&lt;li&gt;Does anyone need clarity or have any concerns?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deadline:&lt;/strong&gt; It’s helpful to know how a deadline is determined to get a sense of how flexible it is (because, hey, unexpected delays happen), as well as how comfortable it feels for the team working on it. A super strict, immovable deadline can require extra support and communication as a project manager.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is the deadline?&lt;/li&gt;
&lt;li&gt;How has the deadline been determined?&lt;/li&gt;
&lt;li&gt;Does it feel loose, comfortable, or tight?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Personnel:&lt;/strong&gt; It’s helpful to establish everyone’s role on the project, make sure they’re clear what‘s expected of them, and determine if any planned outages could impact project progress.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How many and which team members are involved?&lt;/li&gt;
&lt;li&gt;What are their roles in within this project?&lt;/li&gt;
&lt;li&gt;Are there any notable outages to consider?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Budget:&lt;/strong&gt; A project’s budget is determined as a result of setting scope, value, negotiation, and often a certain amount of guesswork (ehem…&lt;a href=&quot;https://twitter.com/lynnandtonic/status/1096126469745434624&quot;&gt;https://twitter.com/lynnandtonic/status/1096126469745434624&lt;/a&gt;). It’s helpful to have a system for monitoring if a project is trending toward exceeding the budget, and a plan for getting it back on track.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is the budget?&lt;/li&gt;
&lt;li&gt;Are there target time contribution ranges for each type of contributor? (Design, Project Management, Dev, etc.)&lt;/li&gt;
&lt;li&gt;If so, what system will be used to monitor the hours throughout the project?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Internal and External Communication:&lt;/strong&gt; At the end of the day, someone has to be opinionated about where and how to communicate. Figuring out how to capture communication where it naturally occurs can greatly improve the flow of ideas and quality of collaboration. When setting communication expectations, it’s important to think about what your team needs to be successful, but also about what &lt;em&gt;you&lt;/em&gt; need from your team in order to keep the project running smoothly. This is also a good time to think about not only how often meetings take place, but also how you can be an effective meeting planner. Perhaps creating an agenda to share with the client prior to the meeting would make the most of a short meeting time. Think about what you need from your teammates in order to do this, and make sure they know to prioritize providing this support.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How do the stakeholders and teammates prefer to communicate? (Slack, email, phone, etc.)&lt;/li&gt;
&lt;li&gt;How often do the stakeholders and teammates prefer to communicate?&lt;/li&gt;
&lt;li&gt;Are there timezone challenges to consider?&lt;/li&gt;
&lt;li&gt;What communication boundaries need to be set? For instance, is it ok for clients to DM individual team members with questions or feedback?&lt;/li&gt;
&lt;li&gt;How should feedback or bugs be reported?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If I don’t know the answer to a question above, I seek it out. If I’m not sure how a stakeholder prefers to communicate, I ask; “What tools does your team use? If we have a quick question or design direction to hash out, how do you feel about hopping on a quick call? How far in advance do you like to have meetings scheduled?”&lt;/p&gt;
&lt;h2 id=&quot;go-beyond-the-basicsor-dont&quot;&gt;&lt;a href=&quot;#go-beyond-the-basicsor-dont&quot; aria-label=&quot;go beyond the basicsor dont permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Go beyond the basics…or don’t&lt;/h2&gt;
&lt;p&gt;If the project that you’re planning for is likely to last for a more than a couple of weeks, it may be helpful to consider the long-term impact on the team involved. Consider more deeply how the cadence and management approach to the project may affect your team.&lt;/p&gt;
&lt;p&gt;I recently held a project retrospective where many people shared that they had all felt a certain level of burnout at some point during the project. After several months of heads down work, it would have been helpful to plan for somewhat of a break, along with an intentional revisiting of the core goals of the project, to enable us to come back to the work with renewed energy and fresh perspective.&lt;/p&gt;
&lt;p&gt;Going beyond the basics requires you to deeply consider the unique needs of your team as contributors, and yourself as a leader. A few folks on my team (&lt;a href=&quot;https://andyet.com/team/heather&quot;&gt;Heather&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/eric&quot;&gt;Eric&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/lynn&quot;&gt;Lynn&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/nathan&quot;&gt;Fritzy&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/luke&quot;&gt;Luke&lt;/a&gt;, and &lt;a href=&quot;https://andyet.com/team/amy&quot;&gt;Amy&lt;/a&gt;) recently formed a ‘Project Management Working Group’ and did some excellent work in outlining what this deeper project prep work looks like:&lt;/p&gt;
&lt;h3 id=&quot;get-to-know-your-team&quot;&gt;&lt;a href=&quot;#get-to-know-your-team&quot; aria-label=&quot;get to know your team permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Get to know your team&lt;/h3&gt;
&lt;p&gt;Being aware of personality types and areas of general strength can help the PM communicate effectively and work through conflicts when they inevitably arise. Getting to know your teammates is one of the most important and effective skills of a project manager. It can be helpful to run through these as a mental checklist at the beginning of every new project, even if you’ve worked with the same people for years.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Who is self-directed and who needs more explicit direction?&lt;/li&gt;
&lt;li&gt;Who is naturally focused on big-picture or long-term and who is focused on the present details?&lt;/li&gt;
&lt;li&gt;What is the team’s capabilities, strengths, and interests?&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Trust can be strongly affected by the presence and quality of project management.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In general people who trust more slowly may need more explicit direction. This is because they see their work in terms of agreements. If there is no verbal or written agreement about what should be done, or if these agreements are violated, they may view a minor oversight as a personal betrayal or violation of trust.&lt;/li&gt;
&lt;li&gt;On the other hand, people who trust more easily may find working on highly-structured project to be constraining or annoying. They extend trust naturally, and may interpret any insistence on procedure to be questioning their competence or reliability.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Visibly appreciate and celebrate your team, especially people who do background work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;let-your-team-get-to-know-you&quot;&gt;&lt;a href=&quot;#let-your-team-get-to-know-you&quot; aria-label=&quot;let your team get to know you permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let your team get to know you&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;What is your leadership style?&lt;/li&gt;
&lt;li&gt;How are you under stress?&lt;/li&gt;
&lt;li&gt;What are your expectations and availability?&lt;/li&gt;
&lt;li&gt;Let them know you are there to make your teams life easier!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whether or not you go beyond the basics when preparing to manage a project is up to you. It depends on some obvious factors (the size or duration of the project), but also some less obvious factors as well (whether or not this is a team that you’ve worked closely with before, whether or not this project feels like old hat or uncharted territory).&lt;/p&gt;
&lt;h2 id=&quot;create-a-process&quot;&gt;&lt;a href=&quot;#create-a-process&quot; aria-label=&quot;create a process permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create a process&lt;/h2&gt;
&lt;p&gt;From here, create a process that makes sense for that project. I’m calling it a ‘process’ for the sake of continuity, but really it’s a framework for communication. The real role of a project manager is to make sure everyone involved has the information they need when they need it, where they need it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Decide what information will live where&lt;/strong&gt; &lt;br&gt;&lt;em&gt;Example:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Slack:&lt;/strong&gt; Ongoing discussion and quick status updates&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dropbox/Dropbox comments:&lt;/strong&gt; Sharing early design iteration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dropbox paper:&lt;/strong&gt; Work plan, checklists, meeting notes, feature specs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Github:&lt;/strong&gt; Milestones, design and dev collaboration, granular UX discussion&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Define a ‘work plan’ that makes sense for this project.&lt;/strong&gt;
A work plan is simply a series of milestones at intervals that make sense for the project. It’s a document visible internally and externally (client-facing), and is very much a living document that changes as circumstances change. Most often a work plan lines out goals or tasks for each week of the project. In some cases, if a project has a very tight deadline, it can be as granular as daily. If a task becomes complicated or priorities change, the work plan changes accordingly.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set internal and external communication expectations&lt;/strong&gt;  &lt;br&gt;&lt;em&gt;Example:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Weekly sync call - 30 minutes, all team members&lt;/li&gt;
&lt;li&gt;Weekly PPP email - PPP stands for Progress, Plans, and Problems/Questions. It’s a formal account of what’s been accomplished that week, as well as next steps for the following week. It&apos;s also a chance to identify any blockers, get clarity where it’s needed, etc. It’s closely aligned with the tasks and milestones outlined in the work plan. The weekly PPP email is a concept that our team has grown very familiar with and have come to appreciate the benefit of. It’s a bit of work to put together, but is very worth it. This email gets sent to both the project participants as well as the client.&lt;/li&gt;
&lt;li&gt;Daily status updates in Slack in the week leading up to a milestone or launch.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/2019/05/23/a-simple-casual-approach-to-blame-free-retrospectives/&quot;&gt;Retrospective meetings&lt;/a&gt; to cap off each major phase or milestone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;vet-your-process&quot;&gt;&lt;a href=&quot;#vet-your-process&quot; aria-label=&quot;vet your process permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Vet your process&lt;/h2&gt;
&lt;p&gt;One of the things I love about how we operate at &amp;#x26;yet is the avoidance of process for the sake of process. What I’ve observed is that before the team is required to adopt a process, it gets vetted to ensure that it has a net positive effect on everyone involved. I think this vetting step is largely unspoken, unofficial and largely unconscious for those who are accustomed to our work culture, but if I were to have to break it down, I’d assume it’s just a matter of asking yourself a few important questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does it require everyone to purchase, create accounts for, buy into, or learn a new tool?&lt;/li&gt;
&lt;li&gt;What are the work styles of everyone involved? Does this process require anyone to fundamentally change how they work or communicate?&lt;/li&gt;
&lt;li&gt;Are there any existing tools or familiar processes that can be emulated or altered to achieve what’s intended?&lt;/li&gt;
&lt;li&gt;Who benefits from this process, and how?&lt;/li&gt;
&lt;li&gt;Who is burdened by this process, and how?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are no right or wrong answers to those questions. I suppose the point of the exercise is to think about the creation of a process with a people-first, empathetic mindset. Do the benefits of the process outweigh the burdens? It also requires that you consider and respect the unique work styles of everyone involved, and to trust that everyone on a project has the same goal in mind, regardless of how they arrive there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After all, the less prescriptive you are about process, the more trust it requires.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ask the people involved what they think of the process. Would they prefer a different way of communicating, or different intervals, or different tools? Tell others what you need from them and ask what they need from you in order to move the project forward. Iterate on you process as you go. Notice pain points, blind spots, or gaps in communication. Scaffold your process where needed, but also back off on meetings for a week or two if it would be more productive for everyone to be heads down. Conversely, notice when increased communication could be useful. Ask your team members how they’re feeling as the project progresses.&lt;/p&gt;
&lt;p&gt;Up until recently, I had gone into projects with the assumption that people wanted to avoid needless meetings whenever possible. I had worked very hard throughout the project to avoid frequent meetings in an effort to respect everyone’s focus and time. I tried very hard to make the meeting schedule sparse, efficient, and generally short and sweet. I learned during the project retrospective that there were times when more frequent meetings may have been helpful for the team. In an effort to avoid imposing a bothersome, interruptive process I had missed the opportunity to provide needed communication support. I now know to ask and to take everyone’s communication temperature throughout the project.&lt;/p&gt;
&lt;h2 id=&quot;live-and-learn&quot;&gt;&lt;a href=&quot;#live-and-learn&quot; aria-label=&quot;live and learn permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Live and learn&lt;/h2&gt;
&lt;p&gt;Iterating on your process as you go is one thing, but sometimes it’s hard to notice where you can improve until the project is done and the team has a chance to take a breath and really think objectively about the project as a whole. Capping each project off with a retrospective is an important exercise (but so easy to forget to do!).  This is also something can be helpful to do at regular intervals throughout the project, or aligned with sprints or milestones.&lt;/p&gt;
&lt;p&gt;Conducting a productive and meaningful retrospective is kind of a topic in and of itself. Even with the most well-meaning, empathetic team, it can be really hard to avoid feelings of blame when discussing something that went wrong in any way.&lt;/p&gt;
&lt;p&gt;A while back I went through a rabbit hole of research on the concept of a blame-free retrospective. I came across some really thorough resources, but ultimately felt like a lot of the proposed methods were extremely dense, formal, and downright intimidating. I was looking for a lightweight, casual guide to having a productive, freeform conversation with my teammates. I ultimately wrote up my own &lt;a href=&quot;/2019/05/23/a-simple-casual-approach-to-blame-free-retrospectives/&quot;&gt;guidelines for a blame-free retrospective&lt;/a&gt;. These guidelines have worked well so far, but I’m always looking to improve and iterate on the retrospective process as well. The concept of a blame-free retrospective is something that I’m very passionate about, and would love to hear what has worked for other teams.&lt;/p&gt;
&lt;p&gt;Project retrospectives are the ultimate way to learn and grow as a team, but also as a way to develop project management methods that are as frictionless, flexible, and ultimately as effective as possible.&lt;/p&gt;
&lt;h2 id=&quot;why-be-unopinionated&quot;&gt;&lt;a href=&quot;#why-be-unopinionated&quot; aria-label=&quot;why be unopinionated permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why be unopinionated?&lt;/h2&gt;
&lt;p&gt;I was inclined to write this post because it seems that project management is often seen as a rigid practice, or even a necessary evil. In reality, it can be an interesting, creative, rewarding practice that anyone can do. In fact, leading a project with a non project management background can be a great advantage.&lt;/p&gt;
&lt;p&gt;You don’t have to have a background in agile development to manage a project efficiently. You only need a basic framework, a people-first mindset, and faith in your own ingenuity to develop a system that works well for you and your team and your clients.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[A simple, casual approach to blame-free retrospectives]]></title><description><![CDATA[Let’s talk about project retrospectives! Project retrospectives (sometimes called post-mortems) are pretty loosely defined as a meeting held…]]></description><link>https://blog.andyet.com/2019/05/23/a-simple-casual-approach-to-blame-free-retrospectives/</link><guid isPermaLink="false">https://blog.andyet.com/2019/05/23/a-simple-casual-approach-to-blame-free-retrospectives/</guid><pubDate>Thu, 23 May 2019 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f2d5f52f149e9ba18fe819532a8e0ced/914ae/blog-illo-retrospectives.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 58.27814569536424%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsSAAALEgHS3X78AAABZ0lEQVQoz6VSy07CQBTli4yf4vf4H640cYNx48IFiQmJIYS4cSEKkpiCqYi1pe/ptNPHPPC0pYgBVp7F5MzNPXPvPXdaq3+gtX1RSiq1wpEkSVEUUooa4JRSQgjIIbFKSDh+ejDMb8e2dV0PwyCsYFkm5zletW1b4fk/4urOqKUNb33PYawsaxiG7/tpmmZZBmIufdslQRDuVpZQG5Or/sXRaHCGuxAc3YJwzlVVazi4nI7u1qnbYsk581Njcj2+P529dhEpKoDkeYZslpBe++SxfbzU+7U1v2Jn9PFy3pVC0aQICY3jGK3mDYo8Q87s+cZ46ziETpdBqd+IYXAaxnBT8LIa5sTAaBbKum0hpGV+eq7X07464/fGpcZtKWW9DM/zXNe1LAsEEbTgOA42h/1lKYsiIqTcWZVa6+fz+WKxQGVN0yCDz4iARFGEcRhjBz/JBkiq3a4BJd4t628teY9Y7cOh7/kDnGSw7HHGP4AAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;A shared document with conversation bubbles, thumbs up, and thumbs down.&quot;
        title=&quot;&quot;
        src=&quot;/static/f2d5f52f149e9ba18fe819532a8e0ced/90cbd/blog-illo-retrospectives.png&quot;
        srcset=&quot;/static/f2d5f52f149e9ba18fe819532a8e0ced/29fe9/blog-illo-retrospectives.png 151w,
/static/f2d5f52f149e9ba18fe819532a8e0ced/6728c/blog-illo-retrospectives.png 303w,
/static/f2d5f52f149e9ba18fe819532a8e0ced/90cbd/blog-illo-retrospectives.png 605w,
/static/f2d5f52f149e9ba18fe819532a8e0ced/914ae/blog-illo-retrospectives.png 860w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let’s talk about project retrospectives! Project retrospectives (sometimes called post-mortems) are pretty loosely defined as a meeting held after the completion of a project during which you discuss your achievements and what the team can do to make improvements in the future. ‘Project’ could mean a contained project that is completely wrapping up, or it could be a phase or major milestone within a larger project.&lt;/p&gt;
&lt;p&gt;Sounds pretty great, right? BUT…Is it possible to love figuring out how to improve as an individual and team, but still not love doing retrospectives? That &lt;em&gt;might&lt;/em&gt; be me (and maybe secretly everyone).&lt;/p&gt;
&lt;p&gt;Though retrospectives may seem simple in concept, they can also bring with them a few challenges to navigate.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Even when the project goes really well, it’s easy for you and the team to feel like you’re mentally &lt;em&gt;done&lt;/em&gt; with a project when it wraps. When your brain is ready to take a break from thinking about something that you’ve been immersed in for a long time, it can be hard to be motivated to take the time to think back, and rehash all of the details of the project.&lt;/li&gt;
&lt;li&gt;Talking about things that didn’t go well takes courage and candor that everyone on the team must be willing to offer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;While talking about achievements as a team is fun and gratifying, discussing the root cause of a project’s pain points can be challenging to do without assigning blame.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recently I went through a rabbit hole of research on the concept of a blame-free retrospective. I came across some really thorough resources, but ultimately felt like a lot of the proposed methods were extremely dense, formal, and downright intimidating. I was looking for a lightweight, casual guide to having a productive, freeform conversation with my teammates after a project. I ultimately decided to develop my own template — a set of loose guidelines that follow a two-step process. These guidelines are copied into a collaborative document and shared with the team a week or so before the scheduled retrospective meeting.&lt;/p&gt;
&lt;p&gt;The first step is intended to be done asynchronously. It offers a few different options for noting observations which are intended to be flexible for different communication styles and sensitive to concerns which some folks may not feel entirely comfortable raising verbally in a meeting. It being a blame-free retrospective, it may go without saying that it’s not productive to call out an individual team or teammate during a retrospective meeting when discussing challenges. If legitimate personnel or team dynamic concerns arise, this template gives people a framework for reflection and an option to flag these concerns with the PM privately. It’s up to the PM to determine how or if these concerns can be raised productively and in a blame-free fashion during the retrospective.&lt;/p&gt;
&lt;p&gt;The second step is intended to synthesize the observations from step 1 into actionable steps, as well as give space for additional questions and thoughts that may arise during the discussion.&lt;/p&gt;
&lt;p&gt;You may wonder, “How is this template inherently blame-free?” In a lot of ways, that depends on how the conversation is led. &lt;strong&gt;Intentional moderation is so important.&lt;/strong&gt; Whether the retrospective is led by the engineering lead, or the project manager (as is the case on our team), the focus must be on examining and improving process vs. targeting individual performance. Looking at pain points as a failure of process is essential in removing the blame from individuals when things go wrong. If something was overlooked in QA, then the QA process must be examined for blind spots or weak points, not the individuals who carry out the process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The team must take ownership of the process, and share the responsibility of creating solutions when they are needed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Also, an important value in the culture of &amp;#x26;yet is inherent trust. It’s not really addressed directly in this template, but when we’re conducting retrospectives at &amp;#x26;yet, we’re all coming to the table with a high level of trust in our teammates, and the understanding that everyone on the project has contributed to the project with the same goals and same commitment to success in mind.&lt;/p&gt;
&lt;p&gt;In general, two main points encapsulate the mindset required for a blame-free retrospective:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A focus on examining and improving process vs. individual performance&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An inherent level of respect and trust in our teammates&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These guidelines have worked well so far, but I’m always looking to improve and iterate on the retrospective process as well. The concept of a blame-free retrospective is something that I’m very interested in, and would love to hear what has worked for other teams.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;project-retrospective-template&quot;&gt;&lt;a href=&quot;#project-retrospective-template&quot; aria-label=&quot;project retrospective template permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Project Retrospective Template:&lt;/h2&gt;
&lt;h3 id=&quot;step-1&quot;&gt;&lt;a href=&quot;#step-1&quot; aria-label=&quot;step 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 1:&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Complete individually prior to the group discussion&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Options:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Posting directly in the doc prior to the meeting&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Making private notes to be shared verbally in the meeting&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Flagging concerns/thoughts/questions privately with the PM&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;List personal or group wins. What worked well?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What were the pain points, and how could the process* be improved to avoid these things in the future?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What was different than expected or surprising about this project, and why?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;* ‘Process’ can be defined as: communication style or method, boundaries, tools used, where communication happens, workflow, etc.&lt;/p&gt;
&lt;h3 id=&quot;step-2&quot;&gt;&lt;a href=&quot;#step-2&quot; aria-label=&quot;step 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 2:&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Complete as a group during the discussion&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Goals for ongoing or future work:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Actionable steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Questions or other thoughts:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;</content:encoded></item><item><title><![CDATA[The Great Gatsby (Blog Transition)]]></title><description><![CDATA[Over the past several years, static sites have had a bit of a rebirth. Heralding back to the days of FTPing plain HTML and CSS files to a…]]></description><link>https://blog.andyet.com/2019/05/21/the-great-gatsby-blog-transition/</link><guid isPermaLink="false">https://blog.andyet.com/2019/05/21/the-great-gatsby-blog-transition/</guid><pubDate>Tue, 21 May 2019 13:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over the past several years, static sites have had a bit of a rebirth. Heralding back to the days of FTPing plain HTML and CSS files to a webserver, static site generators like Jekyll along with static hosts like GitHub Pages and Netlify have brought the power of plain HTML, CSS, and JavaScript to a newer generation of web developers. One particular area that static sites have excelled at is for generating blogs, like this one! In lieu of complicated setups like WordPress that required setting up a PHP environment along with a database, static-site blogs are meant to be simple to get up and running and simple to maintain. Being a forward-thinking group of folks, &amp;#x26;yet has used a static-site for our blog for quite a while now. However, getting it up and running wasn’t exactly as easy as the “Getting Started with Static Sites” tutorials would have lead you to believe. At one point the initial setup was so complicated, and so unreliable for our developers, that we encapsulated the entire application inside a Dockerfile to make development easier. And I don’t know about you, but I don’t think a static-site generator should be so complicated as to require Docker to get up and running.&lt;/p&gt;
&lt;h2 id=&quot;howd-you-manage-that&quot;&gt;&lt;a href=&quot;#howd-you-manage-that&quot; aria-label=&quot;howd you manage that permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How’d you manage that?&lt;/h2&gt;
&lt;p&gt;Our previous site was built using a Python static-site generator. It was incredibly well-featured, and allowed us to do virtually everything we wanted to do. However, that power came at a cost. The code only ran on Python 2, so when macOS updated the system Python from 2 to 3, the Makefile that built the site suddenly stopped working for those working on the site (that was assuming you’d managed to properly install the dependencies the site required in the first place!). While these hurdles are easy to solve for lightly-seasoned Python developers, they were difficult roadblocks for our JavaScript-focused developers (which is the vast majority of our team). Adding Docker support was a bit of an improvement, but it was still asking a lot of our team, especially for something that was supposed to be simple and straightforward!&lt;/p&gt;
&lt;h2 id=&quot;so-how-did-you-fix-it&quot;&gt;&lt;a href=&quot;#so-how-did-you-fix-it&quot; aria-label=&quot;so how did you fix it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So how did you fix it?&lt;/h2&gt;
&lt;p&gt;Right around the time we were fighting with these issues, a little-known JavaScript static-site generator named Gatsby was experiencing a bit of a rise to fame. Gatsby promised to bring the quick initial loading of static sites together with the near-instant loading of a single-page-application while still feeling like a standard React application. The biggest question we had was this: will it be easier than what we have now?&lt;/p&gt;
&lt;p&gt;With Gatsby, this is all that’s needed to get up and running:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;$ git clone --recursive https://github.com/andyet/blog.andyet.com.git
$ cd blog.andyet.com
$ npm install
$ npm start&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thanks to Gatsby, the process for getting up and running with our blog is exactly the same as many of our other React and JavaScript-based projects. It no longer requires a specific version of Python at a specific path, no longer requires installing third-party modules into a global location, and most definitely doesn’t require Docker.&lt;/p&gt;
&lt;h2 id=&quot;it-sounds-easier-but-is-it-better&quot;&gt;&lt;a href=&quot;#it-sounds-easier-but-is-it-better&quot; aria-label=&quot;it sounds easier but is it better permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It sounds easier, but is it better?&lt;/h2&gt;
&lt;p&gt;One of the main reasons we chose Gatsby is that it’s both a static-site generator and a complete React application. This gives us the performance benefits of static-sites along with the client-side performance benefits of single-page applications. When you type in &lt;code class=&quot;language-text&quot;&gt;blog.andyet.com&lt;/code&gt;, the initial response contains all the HTML and CSS necessary for rendering our blog’s homepage. It renders just fine without any JavaScript, and will even work beautifully in a browser with JavaScript disabled. What happens next is the magical bit. Gatsby then “rehydrates” the React application, which handles subsequent navigations. When you click on a blog post title, instead of going to the server and requesting the HTML and CSS all over again, Gatsby requests just the content of the blog post, which is able to be delivered in just a handful of gzipped kilobytes. Gatsby also does some really nifty things like loading the content of the post the moment you mouse over a title, that way when you actually click on it, the blog post’s content has already been retrieved from the network.&lt;/p&gt;
&lt;h2 id=&quot;okay-that-makes-sense-but-how-hard-was-it&quot;&gt;&lt;a href=&quot;#okay-that-makes-sense-but-how-hard-was-it&quot; aria-label=&quot;okay that makes sense but how hard was it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Okay, that makes sense. But how hard was it?&lt;/h2&gt;
&lt;p&gt;Moving from our previous static-site generator to Gatsby was actually surprisingly easy. We store all of our blog posts in a separate repo (hence the &lt;code class=&quot;language-text&quot;&gt;--recursive&lt;/code&gt; flag above), so the only slightly tricky bit was telling Gatsby how to properly parse all of our existing Markdown files. We also had to port a few complex features like related posts and archives, but because our entire team is familiar with JavaScript and React, it was a fairly straightforward operation.&lt;/p&gt;
&lt;p&gt;To start, we copied over all of our style assets, written in Stylus. Thanks to &lt;code class=&quot;language-text&quot;&gt;gatsby-plugin-stylus&lt;/code&gt;, we were able to easily reference our primary stylesheet inside of our default layout component. This ensured that our entire stylesheet was loaded at the root of the application. Our complete stylesheet is only 9KB gzipped, so it’s sent as an inline stylesheet with the initial document. This ensures that after the initial network request, there’s no other render-blocking network request.&lt;/p&gt;
&lt;p&gt;Once we had our stylesheet being loaded, building the rest of the site was basically just copying and pasting the original templates, replacing template strings with their Gatsby-equivalents. Our existing templates were arranged in virtually the same exact way that Gatsby wanted, so the bulk of the modifications were simply replacing &lt;code class=&quot;language-text&quot;&gt;class=&amp;quot;&amp;quot;&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;className=&amp;quot;&amp;quot;&lt;/code&gt; for React.&lt;/p&gt;
&lt;p&gt;As was mentioned earlier, the most complicated portion of the transition was reimplementing two features our previous static-site generator gave us for free: related posts and archives. For related posts, we pick the posts with the highest “tag affinity”, which is basically the posts with the highest number of shared tags with the current post. We then add these related posts to our page context in the call to &lt;code class=&quot;language-text&quot;&gt;createPage&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Our archive pages were also pretty easy to build with Gatsby. We use a year-specific GraphQL query to get a list of all posts for a given year, and then generate a new page listing each of those blog posts. We then provide each page with a list of the years for which we have blog posts, and render a year selector at the bottom of every page.&lt;/p&gt;
&lt;h2 id=&quot;was-it-worth-it&quot;&gt;&lt;a href=&quot;#was-it-worth-it&quot; aria-label=&quot;was it worth it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was it worth it?&lt;/h2&gt;
&lt;p&gt;In the end, the simple fact that our blog’s build process now mirrors the vast majority of our other projects is worth it in and of itself. Along with that, we get a UI system that’s familair to our entire team, the best loading experience from both static sites and client-side rendered applications, and the ability to grow and add other more complex features in the future like service workers.&lt;/p&gt;
&lt;p&gt;So yeah, we think it was worth it!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Assess yourself! Lead generation edition, Part 3]]></title><description><![CDATA[You’ve made it to the final part in our lead generation self-assessment series. High five!To recap, we’re defining lead generation as the…]]></description><link>https://blog.andyet.com/2019/05/14/assess-yourself-lead-generation-edition-part-three/</link><guid isPermaLink="false">https://blog.andyet.com/2019/05/14/assess-yourself-lead-generation-edition-part-three/</guid><pubDate>Tue, 14 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This post is part of a three-part series about assessing your lead generation. Check out the other posts in the series!&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Assess yourself! Lead generation series:&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Part 3&lt;/strong&gt; (You are here)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2019/04/30/assess-yourself-lead-generation-edition-part-two/&apos;&gt;Part 2&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2019/04/17/assess-yourself-lead-generation-edition-part-1/&apos;&gt;Part 1&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;You’ve made it to the final part in our lead generation self-assessment series. High five!&lt;/p&gt;
&lt;p&gt;To recap, we’re defining lead generation as &lt;strong&gt;the strategic application of a deep understanding of your customer that allows you to show up in the right place, at the right time with a welcome solution to a pressing need.&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;Effective lead generation is &lt;strong&gt;a system you have control over, with outcomes that become increasingly predictable and repeatable over time&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Based on this definition, the highest level areas we need to assess are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your understanding of your customer&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Your ability to apply that understanding…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;…to show up in the right place, at the right time&lt;/li&gt;
&lt;li&gt;…to bring a welcome solution to a pressing need&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Your ability to systematize your application of that understanding to bring predictable and repeatable results&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our last post, we helped you assess your ability to apply a deep understanding of your customers to show up in the right place, at the right time with a welcome solution to a pressing need. Now we’re ready to look at the predictability and repeatability of your lead generation system.&lt;/p&gt;
&lt;h2 id=&quot;assessing-the-sustainability-of-your-lead-generation-system&quot;&gt;&lt;a href=&quot;#assessing-the-sustainability-of-your-lead-generation-system&quot; aria-label=&quot;assessing the sustainability of your lead generation system permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Assessing the sustainability of your lead generation system&lt;/h2&gt;
&lt;p&gt;When talking about facilitating strong customer relationships, there is nothing like human interaction. Automation is scalable, but it isn’t relational. Or is it?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The world’s top chess player isn’t a human or a computer, it’s a ‘centaur’ — a hybrid chess-playing team composed of a human and a computer.” —&lt;a href=&quot;https://asunow.asu.edu/20190503-asu-researchers-add-human-ingenuity-automated-security-tool&quot;&gt;Monique Clement&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;1997 was the first time a world chess champion (Garry Kasparov) was defeated by a computer. Since that time, a new field of chess competition has emerged: Centaur Chess—chess played by humans with the aid of computers.&lt;/p&gt;
&lt;p&gt;What is remarkable is that while chess computers can easily defeat the very best humans, when computers are used to augment those same humans, the human + computer combination will win every time.&lt;/p&gt;
&lt;p&gt;Kasparov put it this way:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Weak human + machine + better process was superior to a strong computer alone and, more remarkable, superior to a strong human + machine + inferior process.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can use this same principle to make your lead generation system not only more sustainable and scalable, but more effective.&lt;/p&gt;
&lt;p&gt;A sustainable lead generation system that facilitates strong customer relationships:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Automates the parts of your system that are the same, whether a human does them or not&lt;/li&gt;
&lt;li&gt;Automates the parts that a computer can do better than a human&lt;/li&gt;
&lt;li&gt;Enables highly intelligent, informed human interaction at the highest leverage points where those interactions really matter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But how do you figure out which is which? We’re going to assess that by looking at the phases most lead generation systems have in common.&lt;/p&gt;
&lt;h2 id=&quot;understand-your-potential-customers&quot;&gt;&lt;a href=&quot;#understand-your-potential-customers&quot; aria-label=&quot;understand your potential customers permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Understand your potential customers&lt;/h2&gt;
&lt;p&gt;In this phase, you’re collecting both qualitative and quantitative data. Your team is probably biased toward one or the other (either trusting your gut based on immersion in the market or relying on numbers) but you need both types to build a full picture of who most needs your product and why.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have you identified what you need to know to better understand your customers?&lt;/li&gt;
&lt;li&gt;Have you identified which of this data can be automatically collected and which needs to be collected by humans?&lt;/li&gt;
&lt;li&gt;Do you have a system that captures both types of data and allows you to view them in integrated ways?&lt;/li&gt;
&lt;li&gt;Does your system include regular intervals of reporting and analysis that informs your team’s common understanding of your customer?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;show-up-in-the-right-place-at-the-right-time-with-a-welcome-solution-to-a-pressing-need&quot;&gt;&lt;a href=&quot;#show-up-in-the-right-place-at-the-right-time-with-a-welcome-solution-to-a-pressing-need&quot; aria-label=&quot;show up in the right place at the right time with a welcome solution to a pressing need permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Show up in the right place at the right time with a welcome solution to a pressing need&lt;/h2&gt;
&lt;p&gt;Showing up on the Internet has never been more expensive. Whether you’re using advertising with its obvious out-of-pocket costs and/or some form of content marketing with its less obvious people costs, it’s tempting to try to automate all of it and be done.&lt;/p&gt;
&lt;p&gt;But we all know where that goes. People can tell when there’s no actual caring human behind a company’s “presence”. And they respond accordingly, usually by ignoring it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What types of relevant content get the most response/interaction in the places we’re showing up?&lt;/li&gt;
&lt;li&gt;What types of content are our potential customers sharing with each other in those places?&lt;/li&gt;
&lt;li&gt;How does that compare to our content and the response we’re getting?&lt;/li&gt;
&lt;li&gt;What do content-creators need from our system to create content at that level, both from a creative standpoint and a sustainability one?&lt;/li&gt;
&lt;li&gt;How are we evaluating our content and &quot;bright-spotting&quot; what’s working so we can repeat it?&lt;/li&gt;
&lt;li&gt;How are we getting the most use out of content that has been successful for us?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;educate-leads-and-provide-resources-to-help-them-on-their-path&quot;&gt;&lt;a href=&quot;#educate-leads-and-provide-resources-to-help-them-on-their-path&quot; aria-label=&quot;educate leads and provide resources to help them on their path permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Educate leads and provide resources to help them on their path&lt;/h2&gt;
&lt;p&gt;Once you’ve connected with a potential customer and helped them take the first steps on the path to getting where they want to go, it’s much easier to automate their experience (and you probably should, so everyone has a foundational knowledge of what you want to help them do, be, or experience).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How are we getting permission to educate potential customers and help them on their path?&lt;/li&gt;
&lt;li&gt;What does every new potential customer experience once they’ve started off on the path we’ve created for them?&lt;/li&gt;
&lt;li&gt;Are the education and resources we’re providing sufficient to getting them to the next phase of their growth?&lt;/li&gt;
&lt;li&gt;Do we have tools that allow us to see where people tend to abandon the path and why?&lt;/li&gt;
&lt;li&gt;Where are the highest impact opportunities where human interaction would make a difference?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;qualify-leads-into-prospects&quot;&gt;&lt;a href=&quot;#qualify-leads-into-prospects&quot; aria-label=&quot;qualify leads into prospects permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Qualify leads into prospects&lt;/h2&gt;
&lt;p&gt;Lead qualification nearly always starts as a manual process, but you will eventually get to a point where you have so many leads that this is unsustainable.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How active are we at qualifying leads that express interest in what we’re doing?&lt;/li&gt;
&lt;li&gt;What questions do we ask ourselves to determine whether a lead is right for the solution we’re offering?&lt;/li&gt;
&lt;li&gt;Which questions can be answered and evaluated by a computer?&lt;/li&gt;
&lt;li&gt;Which questions need to be answered and evaluated by a human?&lt;/li&gt;
&lt;li&gt;Does our system allow us to efficiently view which leads are qualified?&lt;/li&gt;
&lt;li&gt;How can our system allow us to be smarter about our leads?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;help-prospects-decide-whether-to-become-a-customer&quot;&gt;&lt;a href=&quot;#help-prospects-decide-whether-to-become-a-customer&quot; aria-label=&quot;help prospects decide whether to become a customer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Help prospects decide whether to become a customer&lt;/h2&gt;
&lt;p&gt;Ideally, your sales materials will be geared toward solving your customer’s problem of needing to decide on a solution. This part can be automated to a large extent. But if there are nuanced challenges in a potential customer’s situation and they can’t confidently find the answer, they are likely to drop off and you won’t hear from them again.&lt;/p&gt;
&lt;p&gt;Identifying the points where someone is having trouble figuring out the answer for their own situation can help you determine the highest leverage points where a human can help move them forward.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How does our system empower potential customers to make the decision that’s right for them, even if that decision is not us?&lt;/li&gt;
&lt;li&gt;How does our system allow us to discover the highest-leverage points for human interaction?&lt;/li&gt;
&lt;li&gt;How does our system enhance our human interactions?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;help-customers-be-successful-on-their-path&quot;&gt;&lt;a href=&quot;#help-customers-be-successful-on-their-path&quot; aria-label=&quot;help customers be successful on their path permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Help customers be successful on their path&lt;/h2&gt;
&lt;p&gt;Helping customers be successful isn’t just about customer service...it’s about identifying their real goals and helping them on the path to getting there.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How well does our system help customers reach the bigger goal behind using our product?&lt;/li&gt;
&lt;li&gt;How does our system help us discover the highest-leverage points for human interaction?&lt;/li&gt;
&lt;li&gt;How does our system enhance our human interactions?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;to-sum-it-up&quot;&gt;&lt;a href=&quot;#to-sum-it-up&quot; aria-label=&quot;to sum it up permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;To sum it up&lt;/h2&gt;
&lt;p&gt;Looking individually at each part of the system is a lot to dig into. But at the highest level, what we really want to know is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What parts of our system could a computer do the same or better?&lt;/li&gt;
&lt;li&gt;What parts need intelligent human interaction?&lt;/li&gt;
&lt;li&gt;How could better automation strengthen those interactions?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Answering these questions is an ongoing process of learning and being curious about the people in front of you and what the data allows you to understand about them. This process is a loop of multiple layers, continually improving as you go.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;&lt;a href=&quot;#further-reading&quot; aria-label=&quot;further reading permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further reading&lt;/h2&gt;
&lt;p&gt;Besides our own research and observations, there are a several resources we’re indebted to for what we know about this stuff. Probably the most impactful is this &lt;a href=&quot;https://vimeo.com/54469442&quot;&gt;talk on the Minimum Badass User&lt;/a&gt; by Kathy Sierra. She also wrote a book called &lt;a href=&quot;https://www.amazon.com/Badass-Making-Awesome-Kathy-Sierra/dp/1491919019&quot;&gt;Badass&lt;/a&gt; that is extremely actionable.&lt;/p&gt;
&lt;p&gt;The concept of the “centaur human” is from &lt;a href=&quot;https://asunow.asu.edu/20190503-asu-researchers-add-human-ingenuity-automated-security-tool&quot;&gt;an article by Monique Clement&lt;/a&gt; describing the findings of a team of cyber-security researchers at ASU.&lt;/p&gt;
&lt;p&gt;I also heard the term bright spotting somewhere else (I think it was in &lt;a href=&quot;https://www.amazon.com/Made-Stick-Ideas-Survive-Others/dp/1400064287&quot;&gt;Made to Stick&lt;/a&gt; by Chip and Dan Heath), but I can’t find that referenced anywhere. Basically the concept is about finding what is really working and putting your system’s resources and energy into that, rather than focusing on fixing what’s broken.&lt;/p&gt;
&lt;p&gt;That’s it for our lead generation self-assessment series! In the next month or so, we’ll be starting a new series on self-assessing your customer referrals. In the meantime, if you have questions about any of these concepts or if you’re considering a lead generation assessment, shoot me an email at sarah@andyet.com. I’d love to help. :)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you haven’t yet, check out &lt;a href=&quot;/2019/04/17/assess-yourself-lead-generation-edition-part-1/&quot;&gt;Part 1&lt;/a&gt; and &lt;a href=&quot;/2019/04/30/assess-yourself-lead-generation-edition-part-two/&quot;&gt;Part 2&lt;/a&gt; of this series.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Assess yourself! Lead generation edition, Part 2]]></title><description><![CDATA[Ready to continue assessing your lead generation? Awesome.To recap from our first post, we’re defining lead generation as the strategic…]]></description><link>https://blog.andyet.com/2019/04/30/assess-yourself-lead-generation-edition-part-two/</link><guid isPermaLink="false">https://blog.andyet.com/2019/04/30/assess-yourself-lead-generation-edition-part-two/</guid><pubDate>Tue, 30 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This post is part of a three-part series about assessing your lead generation. Check out the other posts in the series!&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Assess yourself! Lead generation series:&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2019/05/14/assess-yourself-lead-generation-edition-part-three/&apos;&gt;Part 3&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Part 2&lt;/strong&gt; (You are here)&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2019/04/17/assess-yourself-lead-generation-edition-part-1/&apos;&gt;Part 1&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Ready to continue assessing your lead generation? Awesome.&lt;/p&gt;
&lt;p&gt;To recap from &lt;a href=&quot;https://blog.andyet.com/2019/04/17/assess-yourself-lead-generation-edition-part-1/&quot;&gt;our first post&lt;/a&gt;, we’re defining &lt;strong&gt;lead generation as the strategic application of a deep understanding of your customer that allows you to show up in the right place, at the right time with a welcome solution to a pressing need&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Effective lead generation is &lt;strong&gt;a system you have control over, with outcomes that become increasingly predictable and repeatable over time&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Based on this definition, the highest level areas we need to assess are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.andyet.com/2019/04/17/assess-yourself-lead-generation-edition-part-1/&quot;&gt;Your understanding of your customer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Your ability to apply that understanding…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;…to show up in the right place, at the right time&lt;/li&gt;
&lt;li&gt;…to bring a welcome solution to a pressing need&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Your ability to systematize your application of that understanding to bring predictable and repeatable results&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our last post, we helped you assess your level of understanding of your customers. Now we’re ready to look at how well you’re currently applying that understanding.&lt;/p&gt;
&lt;h2 id=&quot;applying-a-deep-understanding-of-your-customers&quot;&gt;&lt;a href=&quot;#applying-a-deep-understanding-of-your-customers&quot; aria-label=&quot;applying a deep understanding of your customers permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Applying a deep understanding of your customers&lt;/h2&gt;
&lt;p&gt;Once you are confident that you truly understand your customers and the value of your role in that relationship, applying it effectively is a matter of using that knowledge as the basis for your decision-making. This may seem obvious, but it’s easy to hide a lack of customer understanding behind “best practices” that don’t end up being as effective as you’d hoped.&lt;/p&gt;
&lt;p&gt;An effective lead generation system is nuanced based on who you are and who your customers are, but they all have two common components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;where and when you show up&lt;/li&gt;
&lt;li&gt;the value your interaction has to your potential customer&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;showing-up-in-the-right-place-at-the-right-time&quot;&gt;&lt;a href=&quot;#showing-up-in-the-right-place-at-the-right-time&quot; aria-label=&quot;showing up in the right place at the right time permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Showing up in the right place at the right time&lt;/h2&gt;
&lt;p&gt;There is certainly value in showing up in your potential customer’s world in nearly any context, but the potency of that interaction is significantly greater if they are in a frame of mind to be aware, interested, and even pursuing an answer to the problem you can help them with.&lt;/p&gt;
&lt;p&gt;When we’re focused on generating quality leads, those are the interactions we are looking for. We don’t need to show up everywhere, constantly. We need to show up where and when we are needed most.&lt;/p&gt;
&lt;h3 id=&quot;how-are-we-showing-up-in-the-right-place-at-the-right-time&quot;&gt;&lt;a href=&quot;#how-are-we-showing-up-in-the-right-place-at-the-right-time&quot; aria-label=&quot;how are we showing up in the right place at the right time permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How are we showing up in the right place at the right time?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;How well do we understand the events that are happening in our customer’s world to make them realize the urgency of their need?&lt;/li&gt;
&lt;li&gt;Have we identified where they are when this is happening?&lt;/li&gt;
&lt;li&gt;Are we showing up in those places, right when they need us most?&lt;/li&gt;
&lt;li&gt;How crowded are the places we’re showing up? How clearly are our customers able to hear our voice?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bringing-a-welcome-solution-to-a-pressing-need&quot;&gt;&lt;a href=&quot;#bringing-a-welcome-solution-to-a-pressing-need&quot; aria-label=&quot;bringing a welcome solution to a pressing need permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bringing a welcome solution to a pressing need&lt;/h2&gt;
&lt;p&gt;Once we know we’re showing up in the right place at the right time, we need to put ourselves in a position to be as helpful as we can. This involves focusing on the person, the problem, and the path forward rather than focusing on the product. Product awareness will come. The goal here is to establish a trusting relationship in which you are a valued, irreplaceable contributor to where your customer wants to be.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How are we bringing a welcome solution to a pressing need?&lt;/li&gt;
&lt;li&gt;How clearly are we empathizing with the need that they have?&lt;/li&gt;
&lt;li&gt;How clearly are we communicating a new vision for what is possible?&lt;/li&gt;
&lt;li&gt;How clearly are we demonstrating a path for them to get there? &lt;/li&gt;
&lt;li&gt;How easy have we made it for them to take the first step?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our next post, we’re going to walk you through assessing the system that allows you to do this repeatedly and predictably. &lt;/p&gt;
&lt;p&gt;In the meantime, if you have questions about any of these concepts or if you’re considering a &lt;a href=&quot;https://andyet.com/lead-generation-assessment&quot;&gt;lead generation assessment&lt;/a&gt;, shoot me an email at &lt;a href=&quot;mailto:sarah@andyet.com&quot;&gt;sarah@andyet.com&lt;/a&gt;. I’d love to help. :)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you haven’t yet, check out &lt;a href=&quot;/2019/04/17/assess-yourself-lead-generation-edition-part-1/&quot;&gt;Part 1&lt;/a&gt; and &lt;a href=&quot;/2019/05/14/assess-yourself-lead-generation-edition-part-three/&quot;&gt;Part 3&lt;/a&gt; of this series.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Assess yourself! Lead generation edition, Part 1]]></title><description><![CDATA[One of the ways we use creative technology to help our clients strengthen their customer relationships is by assessing their lead generation…]]></description><link>https://blog.andyet.com/2019/04/17/assess-yourself-lead-generation-edition-part-1/</link><guid isPermaLink="false">https://blog.andyet.com/2019/04/17/assess-yourself-lead-generation-edition-part-1/</guid><pubDate>Wed, 17 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&apos;post-series&apos;&gt;
  &lt;p&gt;&lt;em&gt;This post is part of a three-part series about assessing your lead generation. Check out the other posts in the series!&lt;/em&gt;&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;Assess yourself! Lead generation series:&lt;/strong&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2019/05/14/assess-yourself-lead-generation-edition-part-three/&apos;&gt;Part 3&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&apos;/2019/04/30/assess-yourself-lead-generation-edition-part-two/&apos;&gt;Part 2&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;Part 1&lt;/strong&gt; (You are here)&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;One of the ways we use creative technology to help our clients strengthen their customer relationships is by &lt;a href=&quot;https://andyet.com/lead-generation-assessment&quot;&gt;assessing their lead generation system&lt;/a&gt;. Once we can see where their strengths and areas of growth are, we can apply our creativity where it will be most effective.&lt;/p&gt;
&lt;p&gt;As useful as it is to have third-party come in and give insight on what they see (which we’re happy to do when you’re at that point), self-inquiry and reflection are also powerful.&lt;/p&gt;
&lt;p&gt;On a personal level, knowing yourself is the first step to noticing and then changing ingrained behaviors that give you less-than-desirable results. It’s no different on an organizational level. Every day, you make choices based on a number of factors, many driven by how your organization operates by default. In order to make different choices, you need to recognize those default patterns and how they affect your results.&lt;/p&gt;
&lt;p&gt;We’re starting with lead generation because without effective lead gen, none of the other things really matter. It’s also one of the bulkiest and slipperiest areas of strategy to work on, hard to get your hands around and feel like you actually have control over it.&lt;/p&gt;
&lt;h2 id=&quot;what-do-we-mean-by-lead-generation&quot;&gt;&lt;a href=&quot;#what-do-we-mean-by-lead-generation&quot; aria-label=&quot;what do we mean by lead generation permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What do we mean by lead generation?&lt;/h2&gt;
&lt;p&gt;For our purposes, &lt;strong&gt;lead generation is the strategic application of a deep understanding of your customer that allows you to show up in the right place, at the right time with a welcome solution to a pressing need&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Effective lead generation is &lt;strong&gt;a system you have control over, with outcomes that become increasingly predictable and repeatable over time&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Based on this definition, the highest level areas we need to assess are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your understanding of your customer&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Your ability to apply that understanding…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;…to show up in the right place, at the right time&lt;/li&gt;
&lt;li&gt;…to bring a welcome solution to a pressing need&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Your ability to systematize your application of that understanding to bring predictable and repeatable results&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since there’s so much to cover here, we’re going to dig into the first one today.&lt;/p&gt;
&lt;h2 id=&quot;understanding-your-customer&quot;&gt;&lt;a href=&quot;#understanding-your-customer&quot; aria-label=&quot;understanding your customer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Understanding your customer&lt;/h2&gt;
&lt;p&gt;Quantifying the experience of even a single human in a single context is a challenge, much less making meaning out of a whole market full of people, most who you can’t even see.&lt;/p&gt;
&lt;p&gt;Because this is so hard, it’s easy to base your understanding on assumptions &amp;#x26; generalizations that ultimately describe a clichéd “person” that doesn’t exist and worse, doesn’t provide any meaningful framework for decision-making. Even easier is to avoid understanding and describing your customer at all, either because it feels impossible or because you’re afraid of making the wrong choice and alienating the customers you do have.&lt;/p&gt;
&lt;p&gt;It takes courage to commit to understanding and defining your customer in a specific, true, and actionable way. We hope this self-assessment will give you the courage you need to take those steps.&lt;/p&gt;
&lt;h2 id=&quot;questions-to-ask-yourself&quot;&gt;&lt;a href=&quot;#questions-to-ask-yourself&quot; aria-label=&quot;questions to ask yourself permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Questions to ask yourself&lt;/h2&gt;
&lt;p&gt;No matter how complex, the process for understanding is always the same. You research, analyze what you&apos;ve learned, and form a mental model of what it all means. Becoming increasingly knowledgeable about something just means having better and truer mental models. &lt;/p&gt;
&lt;p&gt;Your mental model not only includes who your customer is, but also who you are in relationship to them. Once you know that, you need to be able to clearly communicate that model to others in your organization, so you can make decisions based on a similar plane of understanding.&lt;/p&gt;
&lt;p&gt;These questions will help you see your organization’s strengths and areas of growth. You may not tackle all of them at once, but you’ll get a sense for what is highest priority for you on the path to developing a clear understanding of your customer.&lt;/p&gt;
&lt;h3 id=&quot;how-are-we-listening&quot;&gt;&lt;a href=&quot;#how-are-we-listening&quot; aria-label=&quot;how are we listening permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How are we listening?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Where are we listening to our customers?&lt;/li&gt;
&lt;li&gt;How are we listening to who are customers are?&lt;/li&gt;
&lt;li&gt;How are we listening to what our customers need and are concerned about?&lt;/li&gt;
&lt;li&gt;How are we listening to what our customers want and aspire to?&lt;/li&gt;
&lt;li&gt;How are we listening to the way our customers experience their relationship with us?&lt;/li&gt;
&lt;li&gt;Does our approach include listening at 3 levels: marketing, product development and sales? Where we strongest? Where are we weakest?&lt;/li&gt;
&lt;li&gt;How does our approach include listening outside of the context of our organization, in the wider marketplace? &lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-are-we-learning&quot;&gt;&lt;a href=&quot;#what-are-we-learning&quot; aria-label=&quot;what are we learning permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What are we learning?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;What kind of data are we collecting as we listen? Do we have both quantitative and qualitative data?&lt;/li&gt;
&lt;li&gt;How and where do we collect data?&lt;/li&gt;
&lt;li&gt;How and when do we assess the data?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;have-we-distilled-that-data-into-a-clearly-defined-customer-model&quot;&gt;&lt;a href=&quot;#have-we-distilled-that-data-into-a-clearly-defined-customer-model&quot; aria-label=&quot;have we distilled that data into a clearly defined customer model permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Have we distilled that data into a clearly defined customer model?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;How clearly and specifically are we able to define our customer?&lt;/li&gt;
&lt;li&gt;What major frustrations have we identified as common problems our customers are facing?&lt;/li&gt;
&lt;li&gt;How does our customer currently address those frustrations?&lt;/li&gt;
&lt;li&gt;What does our customer ultimately want? Why do they want that? What will getting it help them do, be, or experience?&lt;/li&gt;
&lt;li&gt;How does our customer currently take steps toward getting what they want?&lt;/li&gt;
&lt;li&gt;How easy is our model to understand by our marketing, product, and salespeople?&lt;/li&gt;
&lt;li&gt;How does our data inform our customer model now? How do we integrate new data into our customer model over time?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;have-we-defined-how-we-fit-into-that-model-and-why-it-matters-to-us&quot;&gt;&lt;a href=&quot;#have-we-defined-how-we-fit-into-that-model-and-why-it-matters-to-us&quot; aria-label=&quot;have we defined how we fit into that model and why it matters to us permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Have we defined how we fit into that model and why it matters to us?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;How do we define ourselves in our relationship with our customer, based on our customer model? &lt;/li&gt;
&lt;li&gt;How do we describe who we are, both internally and publicly?&lt;/li&gt;
&lt;li&gt;Why does it matter to us to perform our role in the relationship?&lt;/li&gt;
&lt;li&gt;What qualifies us to perform this role?&lt;/li&gt;
&lt;li&gt;Why does it matter to our customer that we are the ones performing this role for them?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;how-confident-do-we-feel-in-our-overall-approach-to-understanding-our-customer-how-can-we-improve-it&quot;&gt;&lt;a href=&quot;#how-confident-do-we-feel-in-our-overall-approach-to-understanding-our-customer-how-can-we-improve-it&quot; aria-label=&quot;how confident do we feel in our overall approach to understanding our customer how can we improve it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How confident do we feel in our overall approach to understanding our customer? How can we improve it?&lt;/h3&gt;
&lt;p&gt;In our next post, we’re going to walk you through assessing your ability to apply that understanding, showing up in the right place at the right time with a welcome solution to a pressing need. &lt;/p&gt;
&lt;p&gt;In the meantime, if you have questions about any of these concepts or if you’re considering a &lt;a href=&quot;https://andyet.com/lead-generation-assessment&quot;&gt;lead generation assessment&lt;/a&gt;, shoot me an email at &lt;a href=&quot;mailto:sarah@andyet.com&quot;&gt;sarah@andyet.com&lt;/a&gt;. I’d love to help. :)&lt;/p&gt;
&lt;p&gt;If you&apos;re curious about our framework for strengthening customer relationships, sign up for our mailing list below, and we&apos;ll walk you through it. &lt;/p&gt;
&lt;p&gt;&lt;em&gt;Check out &lt;a href=&quot;/2019/04/30/assess-yourself-lead-generation-edition-part-two/&quot;&gt;Part 2&lt;/a&gt; and &lt;a href=&quot;/2019/05/14/assess-yourself-lead-generation-edition-part-three/&quot;&gt;Part 3&lt;/a&gt; of this series.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Thanks for this bag of trash]]></title><description><![CDATA[Helloooo! Over the past eight months or so, we’ve been doing a lot of pontificating over the meaning of life (and &yet). We now know the…]]></description><link>https://blog.andyet.com/2019/04/09/thanks-for-this-bag-of-trash/</link><guid isPermaLink="false">https://blog.andyet.com/2019/04/09/thanks-for-this-bag-of-trash/</guid><pubDate>Tue, 09 Apr 2019 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Helloooo! Over the past eight months or so, we’ve been doing a lot of pontificating over the meaning of life (and &amp;#x26;yet). We now know the secrets of the universe and are ready to share them with you.&lt;/p&gt;
&lt;p&gt;Just kidding. But we &lt;em&gt;are&lt;/em&gt; ready to share our thoughts on an interesting problem we’ve been focused on.&lt;/p&gt;
&lt;h2 id=&quot;thanks-so-much-for-this-bag-of-trash&quot;&gt;&lt;a href=&quot;#thanks-so-much-for-this-bag-of-trash&quot; aria-label=&quot;thanks so much for this bag of trash permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;“Thanks so much for this bag of trash”&lt;/h2&gt;
&lt;p&gt;We don’t always remember much from the talks we’ve attended, but this past year one of the conferences we went to taught us at least one important lesson—most swag is terrible.&lt;/p&gt;
&lt;p&gt;At this extremely high profile event with thousands of attendees, the comment we heard most often was “thanks for this bag of trash.”&lt;/p&gt;
&lt;p&gt;For a lot of people, this might have been something to briefly commiserate on and forget about, but for us, it fit into a larger pattern we’d been seeing with our clients and colleagues—a problem we were considering making central to our work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;People are less tolerant of marketing and advertising than they’ve ever been.&lt;/strong&gt; This is certainly true at conferences, but it’s even more true online, where the “bag of trash” is in the form of invasive advertising, aggressive growth hacking tactics, and low value content marketing.&lt;/p&gt;
&lt;p&gt;Much of our most impactful work has been designed to solve this problem in one way or another—to use creative technology to strengthen relationships, especially customer relationships. (We’re even solving the conference swag problem for one of our clients now, though it’s still pretty hush hush, as are a lot of the projects we work on.)&lt;/p&gt;
&lt;h2 id=&quot;we-strengthen-customer-relationships-through-creative-technology&quot;&gt;&lt;a href=&quot;#we-strengthen-customer-relationships-through-creative-technology&quot; aria-label=&quot;we strengthen customer relationships through creative technology permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;We strengthen customer relationships through creative technology&lt;/h2&gt;
&lt;p&gt;If you’ve been to &lt;a href=&quot;https://experience.realtimeconf.com&quot;&gt;one&lt;/a&gt; of &lt;a href=&quot;https://andyetconf.com&quot;&gt;our conferences&lt;/a&gt;, you get how important it is to us to create experiences where each person feels seen and valued. &lt;strong&gt;We believe generosity is powerful.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Though we’ve always done work in this area (in fact, our Chief of Strategy has been developing a framework around it for the past 15 years), we haven’t talked much about it publicly. Today, we’re ready to change that.&lt;/p&gt;
&lt;p&gt;In upcoming posts, we’re going to share thoughts and research on strengthening customer relationships to solve pressing business problems—problems like low customer acquisition and retention rates, sales processes that don’t convert, and product and feature launches that don’t perform as well as you’d hoped.&lt;/p&gt;
&lt;p&gt;We’ve also updated &lt;a href=&quot;https://andyet.com&quot;&gt;our website&lt;/a&gt; (complete with helicopters and designed by Lynn Fisher), &lt;a href=&quot;https://andyet.com/services&quot;&gt;our services&lt;/a&gt;, and our newsletter to reflect our focus.&lt;/p&gt;
&lt;p&gt;The best way to get the latest updates on our research and thinking is to &lt;a href=&quot;https://blog.andyet.com/feeds/all.atom.xml&quot;&gt;subscribe via RSS&lt;/a&gt; or our newsletter (when you subscribe, we’ll send you a copy of our framework for strengthening customer relationships; you can sign up below). &lt;/p&gt;
&lt;p&gt;If you’ve got a pressing business problem, get in touch with Sarah at &lt;a href=&quot;mailto:sarah@andyet.com&quot;&gt;sarah@andyet.com&lt;/a&gt; or &lt;a href=&quot;https://andyet.com/services&quot;&gt;take a look at our assessments and capabilities&lt;/a&gt;. We’d love to help.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Long live blogs]]></title><description><![CDATA[Have you heard? Personal blogs are back in a big way.The industry is seeing people and teams moving away from centralized platforms and back…]]></description><link>https://blog.andyet.com/2019/03/12/long-live-blogs/</link><guid isPermaLink="false">https://blog.andyet.com/2019/03/12/long-live-blogs/</guid><pubDate>Tue, 12 Mar 2019 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Have you heard? Personal blogs are back in a big way.&lt;/p&gt;
&lt;p&gt;The industry is seeing people and teams moving away from centralized platforms and back to publishing on personal sites and blogs. Brad Frost &lt;a href=&quot;http://bradfrost.com/blog/post/write-on-your-own-website/&quot;&gt;wrote about it&lt;/a&gt;, Andy Bell created &lt;a href=&quot;https://personalsit.es/&quot;&gt;personalsit.es&lt;/a&gt;, and Signal v Noise &lt;a href=&quot;https://m.signalvnoise.com/signal-v-noise-exits-medium/&quot;&gt;moved away from Medium&lt;/a&gt;, to name a few.&lt;/p&gt;
&lt;p&gt;There’s been a resurgence of RSS which warms our little web hearts.&lt;/p&gt;
&lt;p&gt;(We know a great many of you stayed with and maintained your personal blogs over the years and that warms our hearts too!)&lt;/p&gt;
&lt;p&gt;We totally understand the value of platforms. I personally cut my teeth on blogging (and HTML/CSS) with Livejournal. We had the &amp;#x26;yet blog cross-posting to Medium for a while, too. It definitely got more eyes on our writing. And for those that don’t want to mess with hosting or maintenance, a ready-to-go platform with built-in tools makes writing on the web possible.&lt;/p&gt;
&lt;p&gt;The lack of control over the experience and unclear ownership of content can be major downsides, though.&lt;/p&gt;
&lt;p&gt;We love small, personalized nooks on the web, so we’re stoked to see people moving to and encouraging personal blogs and RSS feeds. And we’re taking part. We’re leaving any posts on Medium that are there, but are now focusing and putting our energy into this little blog right here.&lt;/p&gt;
&lt;p&gt;It’s newly running on &lt;a href=&quot;https://www.gatsbyjs.org/&quot;&gt;Gatsby&lt;/a&gt; (more on that soon) and we have some design improvements and new posts in the works. Subscribe to our &lt;a href=&quot;https://blog.andyet.com/feeds/all.atom.xml&quot;&gt;RSS feed&lt;/a&gt; or stay tuned here!&lt;/p&gt;
&lt;p&gt;Many of our team mates are joining in too. Hey, maybe we should start a blogroll? Gosh, I love the web.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adam Brault - &lt;a href=&quot;https://adambrault.com/&quot;&gt;Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sarah Bray - &lt;a href=&quot;https://www.sarahjbray.com&quot;&gt;Site&lt;/a&gt; - &lt;a href=&quot;https://www.sarahjbray.com/blog?format=rss&quot;&gt;RSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Nathan Fritz - &lt;a href=&quot;http://fritzy.io/&quot;&gt;Site&lt;/a&gt; - &lt;a href=&quot;http://gists.fritzy.io/feeds/all.atom.xml&quot;&gt;RSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dylan Staley - &lt;a href=&quot;https://dstaley.com/&quot;&gt;Site&lt;/a&gt; - &lt;a href=&quot;https://dstaley.com/rss.xml&quot;&gt;RSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Lynn Fisher (meeee) - &lt;a href=&quot;https://lynnandtonic.com&quot;&gt;Site&lt;/a&gt; - &lt;a href=&quot;https://lynnandtonic.com/feed.xml&quot;&gt;RSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[An &yet logo refresh]]></title><description><![CDATA[A visual back-and-forth between the old &yet logo and new.Have you had some work done?Hitting certain age milestones has a tendency to…]]></description><link>https://blog.andyet.com/2019/02/13/an-andyet-logo-refresh/</link><guid isPermaLink="false">https://blog.andyet.com/2019/02/13/an-andyet-logo-refresh/</guid><pubDate>Wed, 13 Feb 2019 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;/andyet-rebrand-blog-size-b15849c4f47cfff6414b9dbb9c643365.gif&quot; alt=&quot;A visual back-and-forth between the old &amp;#x26;yet logo and new.&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;have-you-had-some-work-done&quot;&gt;&lt;a href=&quot;#have-you-had-some-work-done&quot; aria-label=&quot;have you had some work done permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Have you had some work done?&lt;/h2&gt;
&lt;p&gt;Hitting certain age milestones has a tendency to inspire reflection. Sometimes that includes the very literal reflection of staring deeply at our faces in a mirror, questioning: does the person staring back really show the world who we are &lt;em&gt;now?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;2018 marked 10 years of existence for &amp;#x26;yet. Suddenly we found ourselves reflectively daydreaming about ways we might spruce up this older, wiser double-digit version of ourselves. Why not give our decade old logo a mini-facelift?&lt;/p&gt;
&lt;p&gt;Our old logo has been with us since the beginning. It was a quick restyling of something one of our founders came up with (see below). Once we created it, we just ran with it and never really looked back. But after a good, long look in the logo mirror (can logos look at themselves in the mirror?) we saw some clear improvements we could make without completely overhauling everything and doing a total rebrand. (We’ll save that for our &lt;em&gt;next&lt;/em&gt; big birthday 😉).&lt;/p&gt;
&lt;h2 id=&quot;ch-ch-ch-ch-changes&quot;&gt;&lt;a href=&quot;#ch-ch-ch-ch-changes&quot; aria-label=&quot;ch ch ch ch changes permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ch Ch Ch Ch Changes…&lt;/h2&gt;
&lt;p&gt;The main issue with our old logo is weight balance. On the left, we have our “&amp;#x26;,” a bold sans-serif character with virtually no contrast (a font’s “contrast” is the difference between the thinnest and thickest parts of the letters. No contrast means all parts are a uniform width). On the right, “yet” is spelled out with dramatic serifs (those little letter “feet”) and a lot of contrast.&lt;/p&gt;
&lt;p&gt;So what did we do to make these two parts feel more harmonious?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Balanced Weight &amp;#x26; Contrast&lt;/strong&gt;&lt;br&gt;
We thickened the characters on the right until their thickest portions were the same width as the uniform thickness of the ampersand. This helps the two halves feel more unified.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/andyet-logo-letter-thickness-0ad0d5a2e4f3317391f2c87800035227.svg&quot; alt=&quot;Diagram comparing the thickness of letter forms for the old and new logo.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shorter Serifs&lt;/strong&gt;&lt;br&gt;
Shorter, chunkier serifs pair a bit nicer with the bold san serif ampersand. Plus they just look better on a logo.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/andyet-logo-serifs-8507dd76a2cf0a2243483e4ddc50d492.svg&quot; alt=&quot;Diagram comparing the serifs for each version of the logo.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Softer Corners all around&lt;/strong&gt;&lt;br&gt;
Rounding the corners just felt a little more polished and added to the more unified feeling between the two logo parts. We softened both the inner and outer corners, making everything nice and smooth.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/andyet-logo-round-corners-c64e40ce10bbe6ba012285570b1cc739.svg&quot; alt=&quot;Diagram comparing the corners of each version of the logo.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adjustments in spacing and height&lt;/strong&gt;&lt;br&gt;
We evened out some of the letter spacing and played around with the some of the letter heights until we landed on something we thought felt more pleasing to the eye.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/andyet-logo-spacing-height-0d3a8151694ed5bcd214f5b8634cb145.svg&quot; alt=&quot;Diagram comparing the spacing and letter height differences between the two logos.&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/andyet-logo-before-n-after-67a09f50ae90a6c95cb8d6d72e344e63.svg&quot; alt=&quot;The old and new &amp;#x26;yet logos side by side.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our new logo has been deployed across our internet presences, ready for an exciting 2019. We hope you like it as much as we do.&lt;/p&gt;
&lt;p&gt;What changes are you hoping to make this year?&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bonus Content&lt;/strong&gt;&lt;br&gt;
&amp;#x26;yet’s short lived, but true first logo, created by our founder Adam Brault, before he teamed up with Amy, who helped, uh, calm it down.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8600b1a03925dad9e3b2359a9e02178e/c1b63/andyet-logo-old.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 28.47682119205298%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsSAAALEgHS3X78AAAAx0lEQVQY03WQzQ7BUBBG+7KewnOIxBOUFTssNBKLSlWDBUWlqo26WtXLRe/PlEpY0H6LWZ3zZWaktDgCgAGkABwE5+wfkL5gNmeua7jGFbaYqgFp+6GOCfYOm3rfPETaDr0QKJLvFeVYbsobUluHHf/UcNEY40hf6KVqW5mq6ITILfPhR37n0V+yljHwiGzj7j7u+ZeOj20HaYPJcOVY+MoF5K396VMiPj9TK2ajYzIOEj2gZkxDmogMgIKbPwUJE1RA7v/+5SfexVUrO9TKewAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;The original &amp;yet logo that has many more colors plus a talk bubble with an ampersand and exclamation point.&quot;
        title=&quot;&quot;
        src=&quot;/static/8600b1a03925dad9e3b2359a9e02178e/90cbd/andyet-logo-old.png&quot;
        srcset=&quot;/static/8600b1a03925dad9e3b2359a9e02178e/29fe9/andyet-logo-old.png 151w,
/static/8600b1a03925dad9e3b2359a9e02178e/6728c/andyet-logo-old.png 303w,
/static/8600b1a03925dad9e3b2359a9e02178e/90cbd/andyet-logo-old.png 605w,
/static/8600b1a03925dad9e3b2359a9e02178e/a2b88/andyet-logo-old.png 908w,
/static/8600b1a03925dad9e3b2359a9e02178e/c1b63/andyet-logo-old.png 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Sabbaticals and muscle memory]]></title><description><![CDATA[In the middle of 2018, I took a 3-month sabbatical from work. It was something I’d been wanting to do for over a year, while I was…]]></description><link>https://blog.andyet.com/2019/02/06/sabbaticals-and-muscle-memory/</link><guid isPermaLink="false">https://blog.andyet.com/2019/02/06/sabbaticals-and-muscle-memory/</guid><pubDate>Wed, 06 Feb 2019 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the middle of 2018, I took a 3-month sabbatical from work. It was something I’d been wanting to do for over a year, while I was experiencing pretty severe burnout. I’ve previously shared a bit of &lt;a href=&quot;https://vimeo.com/248062321&quot;&gt;what that felt like&lt;/a&gt;. I was able to stabilize myself for a while with significant help from my personal and professional support system. But extended leave was still calling me.&lt;/p&gt;
&lt;p&gt;There were logistical decisions to be made and questions to answer. How long would I need? What kind of financial place would I need to be in? Would &amp;#x26;yet hold my job for me? That all felt easy compared to the more nebulous and philosophical questions on my mind. In hindsight, three months isn’t that long, but our country’s culture has a way of punishing those who step away from work. And it encourages us to punish ourselves.&lt;/p&gt;
&lt;p&gt;I had a lot of thoughts. What if taking time off doesn’t help? What if this time away damages my career in some way? What if I forget things, fall behind?&lt;/p&gt;
&lt;p&gt;What if I lose a part of myself?&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;While on sabbatical, I went to my local gym early one morning to shoot hoops. I hadn’t played in years and I knew the court would be empty. Turns out dudes at the gym don’t usually want a 5’3” Asian chick with glasses on their pick-up basketball team. Go figure.&lt;/p&gt;
&lt;p&gt;I used to play every day growing up and played on lots of teams. I was actually pretty good. Maybe on this break I could ease my way back into it.&lt;/p&gt;
&lt;p&gt;As I walked toward the hoop something happened. I dribbled, I squared up, and I took a shot. Swoosh. My arm lingered vertically in the air. Follow through. I grabbed the ball and took more shots. Swoosh. Swoosh. The ball met the wood floor and returned to my hand. Over and over.&lt;/p&gt;
&lt;p&gt;It’s the first time I’ve cried at the gym. Muscle memory is a hell of a thing. All the work and the practice and the connections you made are still there. Even years later, you pick back up and it’s still you.&lt;/p&gt;
&lt;p&gt;I’d just spent a year or so feeling unsure of where I was, feeling unlike myself in ways I couldn’t reconcile. And then that morning, shooting hoops in an empty L.A. Fitness, there I was.&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;I didn’t do much web work during my break. I unpacked the pile of moving boxes we’d been living out of, tried &lt;a href=&quot;https://twitter.com/lynnandtonic/status/1022871859921006593&quot;&gt;making some things out of wood&lt;/a&gt;, visited &lt;a href=&quot;https://twitter.com/lynnandtonic/status/1018634691732094976&quot;&gt;some cool places in Arizona&lt;/a&gt;, and watched a good helping of reality television. I was surprised by how much I loved my time away. Maybe I could do this forever.&lt;/p&gt;
&lt;p&gt;And when I returned to work and to the web, there I was, again. Sometimes the work just flows out of you. Intuition is built from years of practice. Habits. Muscle memory.&lt;/p&gt;
&lt;p&gt;A connection between disparate skills zapped into place in my brain. The feeling of effortlessly sinking free throws and the joy of combining CSS properties to make visual magic.&lt;/p&gt;
&lt;p&gt;I’ve read a lot about specialists and generalists. T-shaped people and comb-shaped people. None of these have felt right to me. Every thing I do and learn and try makes this complex web of knowledge and experience. Each new thing strengthens the web and makes it more entangled.&lt;/p&gt;
&lt;p&gt;Maybe I’m a web-shaped person, a web builder. A spider-person. A friendly neighborhood Spider-Woman.&lt;/p&gt;
&lt;p&gt;I’m also sort of the Queen of getting out of shape and then back into shape in a weird wave pattern that never ends. I’ve accepted it and stopped pushing against it. And this I’ve learned, is how I work too. Being constantly prolific isn’t the norm for a lot of creative people. It’s ok to create seasonally. Some seasons we’re hibernating and others the work bursts from our fingertips without hesitation.&lt;/p&gt;
&lt;p&gt;It’s good to rest when we need it.&lt;/p&gt;
&lt;p&gt;If I’m stuck on a problem, I take a shower. Clean my bathroom or take a nap. When I return, the answer is right there clear as day. I joke that procrastination is part of my process, but I do mean it. Sometimes seeing the answers, connecting the dots, takes a bit of time away.&lt;/p&gt;
&lt;p&gt;So if it’s calling you, take a break. When you come back, you’ll be there.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Behind the scenes: a remote holiday party]]></title><description><![CDATA[&yet has been remote-friendly for a long time, but right now we’re the most remote we’ve ever been. We have team members in Seattle…]]></description><link>https://blog.andyet.com/2019/01/11/bts-a-remote-holiday-party/</link><guid isPermaLink="false">https://blog.andyet.com/2019/01/11/bts-a-remote-holiday-party/</guid><pubDate>Fri, 11 Jan 2019 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/120be61ab81ed1dcca63454501c4c986/8e1fc/bts-holiday-call.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 50.9933774834437%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAIBBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHuTZMUX//EABkQAAEFAAAAAAAAAAAAAAAAAAIAARAhQv/aAAgBAQABBQLTIbGf/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGBAAAgMAAAAAAAAAAAAAAAAAAAIgIVH/2gAIAQEABj8CGs2H/8QAGxABAAMBAAMAAAAAAAAAAAAAAQARMSFRYZH/2gAIAQEAAT8hHoszI3Re/I6Gz2JRtd8ygwC9hk//2gAMAwEAAgADAAAAEPwP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAQEAAwEBAAAAAAAAAAAAAREAIVFhMXH/2gAIAQEAAT8Q+hoHuYgjxTz7uW8/i4JSLIxymL+QWCV9wAAQ6N//2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Illustration of yeti faces in a video call.&quot;
        title=&quot;&quot;
        src=&quot;/static/120be61ab81ed1dcca63454501c4c986/3cb18/bts-holiday-call.jpg&quot;
        srcset=&quot;/static/120be61ab81ed1dcca63454501c4c986/0a254/bts-holiday-call.jpg 151w,
/static/120be61ab81ed1dcca63454501c4c986/c8fe0/bts-holiday-call.jpg 303w,
/static/120be61ab81ed1dcca63454501c4c986/3cb18/bts-holiday-call.jpg 605w,
/static/120be61ab81ed1dcca63454501c4c986/8e1fc/bts-holiday-call.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x26;yet has been remote-friendly for a long time, but right now we’re the most remote we’ve ever been. We have team members in Seattle, Portland, Folsom, Phoenix, Pennsylvania, and Germany. The folks in Tri-Cities, Washington (a sort of “HQ”) work remotely too from co-working spaces, coffee shops, and home offices.&lt;/p&gt;
&lt;p&gt;We love gathering together, but sometimes it’s just not an option. So this past December we decided to try an all-remote holiday party. Some activities worked really well and others not as much. Here’s a rundown of what we did!&lt;/p&gt;
&lt;h3 id=&quot;-recommendations&quot;&gt;&lt;a href=&quot;#-recommendations&quot; aria-label=&quot; recommendations permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;👍 Recommendations&lt;/h3&gt;
&lt;p&gt;We all gathered in a video call to chat and hang out while we added items to a Recommendations doc: a big list of some of our favorite books, movies, tv shows, podcasts, food, and drinks. So many things to read and try! We shared the &lt;a href=&quot;https://blog.andyet.com/2019/01/08/andyet-recommends&quot;&gt;recommendations on the blog&lt;/a&gt; earlier this week if you want to see the things we’ve been excited about.&lt;/p&gt;
&lt;h3 id=&quot;-holiday-gift-unboxing&quot;&gt;&lt;a href=&quot;#-holiday-gift-unboxing&quot; aria-label=&quot; holiday gift unboxing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;📦 Holiday gift unboxing&lt;/h3&gt;
&lt;p&gt;A group of elves in Tri-Cities put together some holiday boxes for everyone on the team. The boxes were shipped to everyone and we all opened them together on our video call. They were amazing! Inside the boxes were a custom designed t-shirt, hoodie, pint glasses, and stickers by people on the team. There were plenty of snacks, candy, and beverages (including some sparkling cider for a toast). Every person got a personalized limerick and toys and books hand-chosen for them.&lt;/p&gt;
&lt;p&gt;A sample of limericks (crafted by Adam):&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Amy has skills your design covets.&lt;br&gt;
If you ask for her critique of its,&lt;br&gt;
She’s likely to say&lt;br&gt;
It’s nice or okay.&lt;br&gt;
But beware of “I don’t really love it”s.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We all know a Nathan named Fritzy.&lt;br&gt;
His way with architecture’s so glitzy.&lt;br&gt;
If we had the need,&lt;br&gt;
He’d slam code with speed.&lt;br&gt;
Thank God his carpals still have some menisci!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here are a few pics of the unboxing:&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a40f3636bf39963d3adc65213577e4ba/8e1fc/bts-holiday-unboxing-1.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 200%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAoABQDASIAAhEBAxEB/8QAGQABAAMBAQAAAAAAAAAAAAAAAAIDBAEF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAGE3SsVM6rsuxNteUjSJyBP/8QAHBABAQACAwEBAAAAAAAAAAAAAQIDEQATISIy/9oACAEBAAEFAuvExDIfPATnVdDFHPVvL1kZNzP4yLuo0wrlb0L7/8QAGREAAgMBAAAAAAAAAAAAAAAAAAEQESFB/9oACAEDAQE/Ae6IyLLZ/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAR/9oACAECAQE/AZrAn//EACEQAAIBAQkBAAAAAAAAAAAAAAABIQIQERIiMVFhgaFB/9oACAEBAAY/Ar8TxCns3PhluRmw38WKlKdyfSdeLJfo6K2+x0vQiD//xAAbEAEAAgMBAQAAAAAAAAAAAAABABEhMVFBgf/aAAgBAQABPyFNo0+QWwxFrbbs1WxuK6m8dEpyqnqC28Brke1N6RhoDyAKTAFUqoVLL3KWHhecqg052rsv8XJ//9oADAMBAAIAAwAAABDg6r+AL//EABoRAQEAAgMAAAAAAAAAAAAAAAEAESFBYYH/2gAIAQMBAT8QHYXkDE6aJc8S0xdl/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAgEBPxDDBCV205ZAdsL/xAAeEAEAAgIDAQEBAAAAAAAAAAABESEAMUFRYXGRof/aAAgBAQABPxCW7FhZlF0aMKhBFBJTGQBf0YoswA6EGsQiwEdHGuc1k5Sh9xQFIEW+4N4GwIjxjQUUYCL0eZXiUCWess9gFHvV4s2PCL9ysZDUBd9ffchD0CkCe8nWXCmf7n//2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;cardboard boxes filled with tissue-wrapped gifts; a cat with unwrapped tissue paper; a haul of gifts.&quot;
        title=&quot;&quot;
        src=&quot;/static/a40f3636bf39963d3adc65213577e4ba/3cb18/bts-holiday-unboxing-1.jpg&quot;
        srcset=&quot;/static/a40f3636bf39963d3adc65213577e4ba/0a254/bts-holiday-unboxing-1.jpg 151w,
/static/a40f3636bf39963d3adc65213577e4ba/c8fe0/bts-holiday-unboxing-1.jpg 303w,
/static/a40f3636bf39963d3adc65213577e4ba/3cb18/bts-holiday-unboxing-1.jpg 605w,
/static/a40f3636bf39963d3adc65213577e4ba/8e1fc/bts-holiday-unboxing-1.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And a full view of box contents:&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/916dfd39cfdb58ac572894dd8250feec/8e1fc/bts-holiday-unboxing-2.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 74.8344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAQL/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQP/2gAMAwEAAhADEAAAAZ85aNLBRD//xAAcEAACAgIDAAAAAAAAAAAAAAACAwERABITIUL/2gAIAQEAAQUCGeNYsMMBzK178Rdf/8QAFxEBAAMAAAAAAAAAAAAAAAAAAAISMf/aAAgBAwEBPwHVov/EABYRAQEBAAAAAAAAAAAAAAAAAAARAv/aAAgBAgEBPwGpp//EABkQAAMBAQEAAAAAAAAAAAAAAAABESEQYf/aAAgBAQAGPwKNOl3w0jeE5//EABsQAQACAwEBAAAAAAAAAAAAAAEAESExQXGB/9oACAEBAAE/ISRLh4SydL2NReMv2bkIiZH5cFE//9oADAMBAAIAAwAAABDA7//EABcRAAMBAAAAAAAAAAAAAAAAAAABEUH/2gAIAQMBAT8QiRQjp//EABcRAAMBAAAAAAAAAAAAAAAAAAABEWH/2gAIAQIBAT8QcOMxP//EABoQAQADAQEBAAAAAAAAAAAAAAEAESFBUWH/2gAIAQEAAT8QZFKUaR97KB0mno+QC2DmzIpaFmw2/wC6KB5EIFiWbP/Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;cardboard box filled with goodies like books, snacks, tshirts, and holiday lights.&quot;
        title=&quot;&quot;
        src=&quot;/static/916dfd39cfdb58ac572894dd8250feec/3cb18/bts-holiday-unboxing-2.jpg&quot;
        srcset=&quot;/static/916dfd39cfdb58ac572894dd8250feec/0a254/bts-holiday-unboxing-2.jpg 151w,
/static/916dfd39cfdb58ac572894dd8250feec/c8fe0/bts-holiday-unboxing-2.jpg 303w,
/static/916dfd39cfdb58ac572894dd8250feec/3cb18/bts-holiday-unboxing-2.jpg 605w,
/static/916dfd39cfdb58ac572894dd8250feec/8e1fc/bts-holiday-unboxing-2.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;
&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/492427e1bde0b8ba7dce56cda41cd4c9/8e1fc/bts-holiday-unboxing-3.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 74.8344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAwACBP/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAEnDEW1xQ//xAAcEAABBAMBAAAAAAAAAAAAAAABAAIDERIhIjH/2gAIAQEAAQUCdYbcatZcnwy7/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8Bqv/EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAECAQE/AYj/xAAaEAACAgMAAAAAAAAAAAAAAAAAAQIREBIx/9oACAEBAAY/ArFq8ONCOH//xAAbEAADAQEAAwAAAAAAAAAAAAAAAREhMUFxgf/aAAgBAQABPyHoPg2LoivsexzsO1DLB+JhKHUP/9oADAMBAAIAAwAAABBLD//EABcRAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQMBAT8Q24Qf/8QAFREBAQAAAAAAAAAAAAAAAAAAEQD/2gAIAQIBAT8QBK//xAAcEAEAAwEBAAMAAAAAAAAAAAABABEhUTFBwdH/2gAIAQEAAT8QCQDMf7E6kkKdxbsC1efFw1AhTnb7BpYqVNO+/Uv2LF3U/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;a spread of gifts including books, snacks, tshirts, and stickers.&quot;
        title=&quot;&quot;
        src=&quot;/static/492427e1bde0b8ba7dce56cda41cd4c9/3cb18/bts-holiday-unboxing-3.jpg&quot;
        srcset=&quot;/static/492427e1bde0b8ba7dce56cda41cd4c9/0a254/bts-holiday-unboxing-3.jpg 151w,
/static/492427e1bde0b8ba7dce56cda41cd4c9/c8fe0/bts-holiday-unboxing-3.jpg 303w,
/static/492427e1bde0b8ba7dce56cda41cd4c9/3cb18/bts-holiday-unboxing-3.jpg 605w,
/static/492427e1bde0b8ba7dce56cda41cd4c9/8e1fc/bts-holiday-unboxing-3.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;All the hand-chosen toys and books for everyone on the team:&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c152360b946a5c84b995af9b936f2c70/8e1fc/bts-holiday-unboxing-4.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 197.35099337748346%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAnABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAIDAf/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAABx5V4cFLVVnaGqsoEsN//xAAcEAACAwEAAwAAAAAAAAAAAAABAgAREiIDEyH/2gAIAQEAAQUCOQ5+w0JXHNSlMWtU0wt5BddKCdP5b9rcz//EABcRAQADAAAAAAAAAAAAAAAAABAAEiH/2gAIAQMBAT8BmFX/xAAWEQEBAQAAAAAAAAAAAAAAAAAQEQD/2gAIAQIBAT8B1K//xAAhEAACAQIGAwAAAAAAAAAAAAAAAQIRIQMSMUFRcUJhgf/aAAgBAQAGPwKLjYxKGpGm7MsrezYwynjnLJNEU39ElpK3RSMVTsXNLCi9zLwf/8QAHhABAAICAgMBAAAAAAAAAAAAAQARITFBUWFxgaH/2gAIAQEAAT8hpABzEhIlzAzmAV3qPCTTSBzyi9C+QUB3tNwWLofMp9QbiO65TBcFFlKFPsg5/sE6Aie8duxTZEswa1P/2gAMAwEAAgADAAAAEKzRAXf/AP/EABkRAQEBAQEBAAAAAAAAAAAAAAEAESExcf/aAAgBAwEBPxDDZ68vsJ7sqWt//8QAGREAAwADAAAAAAAAAAAAAAAAAAERECFx/9oACAECAQE/ELNiY4Rn/8QAHhABAQACAgMBAQAAAAAAAAAAAREAITFBUYGRYdH/2gAIAQEAAT8QZiqhbWzvvNgPBNghX7mrUDQNH5vF0Q1obFfeVDiV23FL71kpGS2fOcABsEIXOoCkO4yr4wPO/HI+YKgLAlJ/dZU8OgAxnfFyKIPIUaWRzMKSuFlpz8cI4qqF5lZlZ8xiXbn/2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;an array of unique toys and books.&quot;
        title=&quot;&quot;
        src=&quot;/static/c152360b946a5c84b995af9b936f2c70/3cb18/bts-holiday-unboxing-4.jpg&quot;
        srcset=&quot;/static/c152360b946a5c84b995af9b936f2c70/0a254/bts-holiday-unboxing-4.jpg 151w,
/static/c152360b946a5c84b995af9b936f2c70/c8fe0/bts-holiday-unboxing-4.jpg 303w,
/static/c152360b946a5c84b995af9b936f2c70/3cb18/bts-holiday-unboxing-4.jpg 605w,
/static/c152360b946a5c84b995af9b936f2c70/8e1fc/bts-holiday-unboxing-4.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This was a really special activity and we already have some fun ideas for the next time we do it.&lt;/p&gt;
&lt;h3 id=&quot;🥂-toasts&quot;&gt;&lt;a href=&quot;#%F0%9F%A5%82-toasts&quot; aria-label=&quot;🥂 toasts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🥂 Toasts&lt;/h3&gt;
&lt;p&gt;We popped open the sparkling cider in our gift boxes to give a round of toasts. One of my very favorite activities &amp;#x26;yet does is going around the group giving toasts on special occasions. They’re always entertaining, heartfelt, and we make sure to get to everyone, no matter how long it takes.&lt;/p&gt;
&lt;p&gt;It’s an opportunity to share personal wins, things that were hard for us over the year, to express gratitude, and to extend high-fives to our teammates.&lt;/p&gt;
&lt;h3 id=&quot;-stardew-valley-group-game&quot;&gt;&lt;a href=&quot;#-stardew-valley-group-game&quot; aria-label=&quot; stardew valley group game permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🌱 Stardew Valley group game&lt;/h3&gt;
&lt;p&gt;After toasts we broke up into groups and played &lt;a href=&quot;https://www.stardewvalley.net/&quot;&gt;Stardew Valley&lt;/a&gt; together. Some people were experienced Stardew-ers and some were novices (me, I had no idea what was going on). It was especially hilarious hearing people’s confused commentary. “Wait, it’s time to sleep? There’s someone in the bed already!”&lt;/p&gt;
&lt;p&gt;This was also a good point in the day for people to step away and take a break. Being present on a group video call can take a lot of energy and some people snuck away for a nap. We’re pro nap-taking, for sure.&lt;/p&gt;
&lt;h3 id=&quot;-pizza&quot;&gt;&lt;a href=&quot;#-pizza&quot; aria-label=&quot; pizza permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🍕 Pizza&lt;/h3&gt;
&lt;p&gt;The next part might be the most important. As much as was possible, everyone on the team got their favorite pizza delivered to their house for lunch. I did some pre-party sleuthing, asking everyone about their fave pizza where they live. Adam correctly assumed that pizza questions coming from me would seem less suspicious. With the help of food delivery services and some friends willing to help out, we all chowed down on some delicious pizza.&lt;/p&gt;
&lt;p&gt;Also we forgot about time zones, so we weren’t all eating at &lt;em&gt;exactly&lt;/em&gt; the same time. But close!&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/56c53efb06fdde4070e792d954324a70/8e1fc/bts-holiday-pizza.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 66.88741721854305%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEBf/EABYBAQEBAAAAAAAAAAAAAAAAAAECA//aAAwDAQACEAMQAAABW7PrzuYuE//EABsQAAIDAAMAAAAAAAAAAAAAAAACAQMSERMi/9oACAEBAAEFAo4PTFvZDu2CLcjLuf/EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/Aaf/xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPwGH/8QAGhABAAIDAQAAAAAAAAAAAAAAABEhAQIxcf/aAAgBAQAGPwKuPFKY1hL/xAAbEAADAAMBAQAAAAAAAAAAAAAAAREhMVFBYf/aAAgBAQABPyFG2bYkGpEnB40mPg1F1xnpql2LzZg//9oADAMBAAIAAwAAABB47//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAwEBPxAs1//EABURAQEAAAAAAAAAAAAAAAAAAAEA/9oACAECAQE/EIKX/8QAGhABAQADAQEAAAAAAAAAAAAAAREAITFBYf/aAAgBAQABPxDqCavnzCXILacYyIIZtgLQaIhc5uxpXuGUtRJeZ//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;A fancy balsamic glazed pizza and an empty pizza box.&quot;
        title=&quot;&quot;
        src=&quot;/static/56c53efb06fdde4070e792d954324a70/3cb18/bts-holiday-pizza.jpg&quot;
        srcset=&quot;/static/56c53efb06fdde4070e792d954324a70/0a254/bts-holiday-pizza.jpg 151w,
/static/56c53efb06fdde4070e792d954324a70/c8fe0/bts-holiday-pizza.jpg 303w,
/static/56c53efb06fdde4070e792d954324a70/3cb18/bts-holiday-pizza.jpg 605w,
/static/56c53efb06fdde4070e792d954324a70/8e1fc/bts-holiday-pizza.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;
&lt;small style=&apos;text-align:center;display:block;&apos;&gt;Not much evidence of the pizza. Too busy eating.&lt;/small&gt;&lt;/p&gt;
&lt;h3 id=&quot;-art-contest&quot;&gt;&lt;a href=&quot;#-art-contest&quot; aria-label=&quot; art contest permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🎨 Art contest&lt;/h3&gt;
&lt;p&gt;Inside our holiday boxes was some assorted-colors Sculpey modeling clay. Sarah’s daughter Lilah gave us a quick tutorial on creating mini clay sculptures and challenged us to create our own. Some &lt;em&gt;beautiful&lt;/em&gt; Sculpey creations were shared (see below) and Lilah judged them and handed out awards. Overall winner was Terry with her wizard (“You’re a wizard, Terry!”). Some other notable awards were “Most Delicious”, “Fastest”, and “Most Fingerprints.”&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ceaae20fc24802c097a6c5354b6cf126/8e1fc/bts-holiday-sculpey.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 198.01324503311258%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAoABQDASIAAhEBAxEB/8QAGQABAAMBAQAAAAAAAAAAAAAAAAIDBAEF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAGtdmy7nim3ostjhIiZBP/EABwQAAIDAAMBAAAAAAAAAAAAAAECAAMREhMiMf/aAAgBAQABBQK4sAFBKKrAt2yyhyzVuDXsLDDRa8zGb5xhb3vKG3rP/8QAGREAAgMBAAAAAAAAAAAAAAAAEBEAARIh/9oACAEDAQE/AUrY7Mn/xAAXEQADAQAAAAAAAAAAAAAAAAAAEBEh/9oACAECAQE/AbVhX//EACAQAAIBAwQDAAAAAAAAAAAAAAABEQISQSEiMVEycaH/2gAIAQEABj8CaxORVzF2Oiam0/Yh1acm4S6LKat05E7fo5pFTykaSjyHJbyf/8QAHBABAAMBAQADAAAAAAAAAAAAAQARITFRQWGR/9oACAEBAAE/IWUCRgivu1SG9scjJCrcWGt3xUqQL7sHgbLSQ2xp8D9mUGirrC4bTsvmVXUMYLwWMqkj08lDXxq/qbAV7c//2gAMAwEAAgADAAAAEOfuwnPP/8QAGREAAwADAAAAAAAAAAAAAAAAAAEREEFR/9oACAEDAQE/EJ6CE2wkZWf/xAAYEQEBAQEBAAAAAAAAAAAAAAABABEhEP/aAAgBAgEBPxARCMDp4xDxsL//xAAfEAEBAAMAAgIDAAAAAAAAAAABEQAhQTFRYaFxgZH/2gAIAQEAAT8QWedQLZC+GfGLDaqHtp/My4Bxj459THLfLUo3x+sZzYSys5qZBsz2U95Ug7hEGg63d5IyTby4tdwlJmjXb613AZJDeTHZhVtg9+8bZ9uAH8xipXQPMJ80BnkdzSOA0Nj4mvWf/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;An assortment of clay sculptures including a wizard, Buddy the Elf and a narwhal, a guy being eaten by another guy, a pizza, a hamburger, Donkey Kong’s head, a guy wearing headphones, a blue car, and a Santa head.&quot;
        title=&quot;&quot;
        src=&quot;/static/ceaae20fc24802c097a6c5354b6cf126/3cb18/bts-holiday-sculpey.jpg&quot;
        srcset=&quot;/static/ceaae20fc24802c097a6c5354b6cf126/0a254/bts-holiday-sculpey.jpg 151w,
/static/ceaae20fc24802c097a6c5354b6cf126/c8fe0/bts-holiday-sculpey.jpg 303w,
/static/ceaae20fc24802c097a6c5354b6cf126/3cb18/bts-holiday-sculpey.jpg 605w,
/static/ceaae20fc24802c097a6c5354b6cf126/8e1fc/bts-holiday-sculpey.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;️-try-to-play-a-game-of-telestrations-but-dont&quot;&gt;&lt;a href=&quot;#%EF%B8%8F-try-to-play-a-game-of-telestrations-but-dont&quot; aria-label=&quot;️ try to play a game of telestrations but dont permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;✏️ Try to play a game of Telestrations, but… don’t&lt;/h3&gt;
&lt;p&gt;Telestrations is a group game that’s a mix of Telephone and Pictionary and it’s hilarious. We’ve played it in person together and hoped we could replicate that experience remotely. We tried an app called &lt;a href=&quot;https://drawception.com/&quot;&gt;Drawception&lt;/a&gt; but it didn’t quite work how we were expecting. After some “Does this work for you?” back and forths, we gave up. But! It did give us an idea of how we could prepare better and try again next time.&lt;/p&gt;
&lt;h3 id=&quot;-white-elephant-gift-exchange&quot;&gt;&lt;a href=&quot;#-white-elephant-gift-exchange&quot; aria-label=&quot; white elephant gift exchange permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🎁 White Elephant gift exchange&lt;/h3&gt;
&lt;p&gt;Another holiday tradition we tried remotely was a White Elephant gift exchange (Yankee Swap, as it’s known to some). It was a little make-shift with us using a combination video call, Slack, and a Paper doc. All the participants selected a $20 gift in advance. We drew names to assign the selection order. If someone chose your gift, you pasted the URL to the gift in Slack. Then we tracked everything in Paper and selecting / stealing gifts continued.&lt;/p&gt;
&lt;p&gt;We lost a little bit of the anonymity that an in-person gift exchange provides, but pasting the gift URLs was still a really fun reveal. And stealing was still as merciless as ever. At the end we ordered and shipped the gifts to the recipient.&lt;/p&gt;
&lt;p&gt;A few of the gifts that showed up in the exchange were a Funko Pop of Bob Ross, a Golden Girls puzzle, a Star Trek cats calendar, a sloth hanging planter, a pizza beach blanket, a Han Solo cutting board, a Jon Kitna autographed football card, a handful of board games, and a book about mushrooms with &lt;a href=&quot;https://www.amazon.com/All-That-Rain-Promises-More/dp/0898153883/ref=sr_1_5?ie=UTF8&amp;#x26;qid=1547219938&amp;#x26;sr=8-5&amp;#x26;keywords=mushroom+book+identifying&quot;&gt;the best cover ever&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0b08fedf1844b2140528bbe767ac9af2/8e1fc/bts-holiday-gift-exchange.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 119.86754966887419%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAYABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAMEAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB305yy7UCUiHoiv/EABoQAQEBAAMBAAAAAAAAAAAAAAIBAwAREiH/2gAIAQEAAQUCtvSqIy0tkUquqpzxZOf1oMU+uf/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB4QAAEDBAMAAAAAAAAAAAAAAAEAAhEDEiFBIjFR/9oACAEBAAY/AqnPeE8gydI3A9+JwtU029yPVl6fLdqmKbS0TmCuS//EABsQAAMBAAMBAAAAAAAAAAAAAAERIQAxQVFx/9oACAEBAAE/IT2EAgQmY8qKcrFrxmkxJhL9xe+TInWXXE3vPMcGjcUiIy0igbi83//aAAwDAQACAAMAAAAQ4/iA/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAREP/aAAgBAwEBPxB2wh5//8QAFhEBAQEAAAAAAAAAAAAAAAAAARBB/9oACAECAQE/EBMiT//EABwQAQEAAwEBAQEAAAAAAAAAAAERACExUUFxkf/aAAgBAQABPxBBspo2461kFLhVrQ6T1yiLo1TB8ntzYa1ivF3jZngoAEgSdf5m+GdNGjW3BN0Ugho9/DEVlsIqFWnwzhWvh4z/2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;An assortment of gifts including board games, Funko Pop figures, books, and trinkets.&quot;
        title=&quot;&quot;
        src=&quot;/static/0b08fedf1844b2140528bbe767ac9af2/3cb18/bts-holiday-gift-exchange.jpg&quot;
        srcset=&quot;/static/0b08fedf1844b2140528bbe767ac9af2/0a254/bts-holiday-gift-exchange.jpg 151w,
/static/0b08fedf1844b2140528bbe767ac9af2/c8fe0/bts-holiday-gift-exchange.jpg 303w,
/static/0b08fedf1844b2140528bbe767ac9af2/3cb18/bts-holiday-gift-exchange.jpg 605w,
/static/0b08fedf1844b2140528bbe767ac9af2/8e1fc/bts-holiday-gift-exchange.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;-movie&quot;&gt;&lt;a href=&quot;#-movie&quot; aria-label=&quot; movie permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🍿 Movie&lt;/h3&gt;
&lt;p&gt;To end the day, we voted on a movie to watch together in &lt;a href=&quot;https://www.rabb.it/&quot;&gt;rabb.it&lt;/a&gt;. We landed on &lt;a href=&quot;https://www.imdb.com/title/tt0371724/&quot;&gt;&lt;em&gt;The Hitchhiker’s Guide to the Galaxy&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt; A handful of us made it to the end and it was a good way to relax and start our winter break.&lt;/p&gt;
&lt;h3 id=&quot;-thoughts&quot;&gt;&lt;a href=&quot;#-thoughts&quot; aria-label=&quot; thoughts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;💭 Thoughts&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It seems like a lot of activities for a day, but it gave people the opportunity to participate in some and excuse themselves from others.&lt;/li&gt;
&lt;li&gt;The gift boxes were really a success. I think next time we do this, more people will have ideas on what to include and they’ll be even bigger.&lt;/li&gt;
&lt;li&gt;Some of the games needed prep before the party and some manual coordination during. With a small group (there’s twenty of us), it wasn’t too bad to manage all that.&lt;/li&gt;
&lt;li&gt;Since we couldn’t gather in person, this was a special way for us to still be together and to celebrate the year and kick off a restful break from work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;-for-next-time&quot;&gt;&lt;a href=&quot;#-for-next-time&quot; aria-label=&quot; for next time permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;💡 For next time&lt;/h3&gt;
&lt;p&gt;Some other ideas we had that we might try for another party in the future:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scavenger hunt&lt;/li&gt;
&lt;li&gt;Blind Skittles taste test (we actually did send everyone Skittles for this, but didn’t get to it. We figured we’d try it at our next all-hands, but some people ate their Skittles already. Can’t say I blame them! 😂)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://talkylander.com/&quot;&gt;Talky Lander&lt;/a&gt; tournament (although Fritzy would surely win)&lt;/li&gt;
&lt;li&gt;Pet holiday costume parade&lt;/li&gt;
&lt;li&gt;Make a group-curated playlist that we listen to during the party&lt;/li&gt;
&lt;li&gt;Holiday story time by the fire&lt;/li&gt;
&lt;li&gt;Robbie Augspurger’s famous &lt;a href=&quot;http://bmoviebingo.com/how-to-play/&quot;&gt;B-movie Bingo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Have you ever tried out a remote gathering? What worked for you? We’d love to hear!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[&yet recommends]]></title><description><![CDATA[In December the &yet team had an all-day, all-remote holiday party. One of our activities was live-collaborating on a Recommendations doc…]]></description><link>https://blog.andyet.com/2019/01/08/andyet-recommends/</link><guid isPermaLink="false">https://blog.andyet.com/2019/01/08/andyet-recommends/</guid><pubDate>Tue, 08 Jan 2019 10:23:00 GMT</pubDate><content:encoded>&lt;p&gt;In December the &amp;#x26;yet team had an all-day, all-remote holiday party. One of our activities was live-collaborating on a Recommendations doc for all the things we enjoyed throughout 2018 (and earlier years too). There’s some good stuff in here so we figured we’d share it with you!&lt;/p&gt;
&lt;p&gt;(Things are organized in the order they were added and include some comments that were left in the document, too.)&lt;/p&gt;
&lt;h2 id=&quot;books-nonfiction&quot;&gt;&lt;a href=&quot;#books-nonfiction&quot; aria-label=&quot;books nonfiction permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Books (nonfiction)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;One From Many&lt;/em&gt;&lt;/strong&gt; by Dee Hock&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Principles&lt;/em&gt;&lt;/strong&gt; by Ray Dalio&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Let Your Life Speak&lt;/em&gt;&lt;/strong&gt; by Parker Palmer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Omnivore&apos;s Dilemma: A Natural History of Four Meals&lt;/em&gt;&lt;/strong&gt; by Michael Pollan&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Hello World: Being Human in the Age of Algorithms&lt;/em&gt;&lt;/strong&gt; by Dr. Hannah Fry&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Untethered Soul: The Journey Beyond Yourself&lt;/em&gt;&lt;/strong&gt; by Michael Singer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Art of Gathering: How we meet and why it matters&lt;/em&gt;&lt;/strong&gt; by Priya Parker&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Folded Clock&lt;/em&gt;&lt;/strong&gt; by Heidi Julavitz&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Ask Baba Yaga: Otherworldly Advice for Everyday Troubles&lt;/em&gt;&lt;/strong&gt; by Taisa Kitaiskaia&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;A Hidden Wholeness: The Journey Toward an Undivided Life&lt;/em&gt;&lt;/strong&gt; by Parker Palmer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Dance of Intimacy&lt;/em&gt;&lt;/strong&gt; by Harriet Lerner&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;A Soprano on Her Head&lt;/em&gt;&lt;/strong&gt; by Eloise Ristad&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Chairs Are Where the People Go: How to Live, Work, and Play in the City&lt;/em&gt;&lt;/strong&gt; by Misha Glouberman&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Teaching a Stone to Talk&lt;/em&gt;&lt;/strong&gt; by Annie Dillard&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Artist’s Way&lt;/em&gt;&lt;/strong&gt; by Julia Cameron&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Creative Habit&lt;/em&gt;&lt;/strong&gt; by Twyla Tharp&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Courage to be Diskliked&lt;/em&gt;&lt;/strong&gt; by Ichiro Kishimi and Fumitake Koga&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Positive Intelligence&lt;/em&gt;&lt;/strong&gt; by Shirzad Chamine &lt;br&gt;📝 &lt;em&gt;+1&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Subtle Art of Not Giving a F*ck&lt;/em&gt;&lt;/strong&gt; by Mark Manson&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Seven Day Weekend&lt;/em&gt;&lt;/strong&gt; by Ricardo Semler&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;How To Change Your Mind&lt;/em&gt;&lt;/strong&gt; by Michael Pollan&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Born a Crime&lt;/em&gt;&lt;/strong&gt; by Trevor Noah&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;books-fiction&quot;&gt;&lt;a href=&quot;#books-fiction&quot; aria-label=&quot;books fiction permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Books (fiction)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Three Body Problem&lt;/em&gt;&lt;/strong&gt; trilogy &lt;br&gt;📝 &lt;em&gt;The first is great, the second is amazing, and the third is ambitious. definitely worth reading all three.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Eyes of the Dragon&lt;/em&gt;&lt;/strong&gt; by Stephen King &lt;br&gt;📝 &lt;em&gt;Great entry point to the SK universe if you’ve ever been curious. This isn’t horror either, 100% fantasy.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;An Absolutely Remarkable Thing&lt;/em&gt;&lt;/strong&gt; by Hank Green&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Eyre Affair&lt;/em&gt;&lt;/strong&gt; by Jasper Fforde&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Turtles All the Way Down&lt;/em&gt;&lt;/strong&gt; by John Green &lt;br&gt;📝 &lt;em&gt;+1&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Mistborn&lt;/em&gt;&lt;/strong&gt; series (or anything really) by Brandon Sanderson&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;I Am Pilgrim&lt;/em&gt;&lt;/strong&gt; by Terry Hayes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Akata Witch&lt;/em&gt;&lt;/strong&gt; by Nnedi Okorafor&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Shadow of the Wind&lt;/em&gt;&lt;/strong&gt; by Carlos Ruiz Zafon&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Norwegian Wood&lt;/em&gt;&lt;/strong&gt; by Haruki Murakami&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Little Fires Everywhere&lt;/em&gt;&lt;/strong&gt; by Celeste Ng&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Dark Matter&lt;/em&gt;&lt;/strong&gt; by Blake Crouch&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Juliet, Naked&lt;/em&gt;&lt;/strong&gt; by Nick Hornby&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Vision&lt;/em&gt;&lt;/strong&gt; Volumes 1 &amp;#x26; 2 by Tom King (comic)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Comet in Moominland&lt;/em&gt;&lt;/strong&gt; by Tove Jansson (and any Moomin book)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;The Kingkiller Chronicle&lt;/em&gt;&lt;/strong&gt; (series) By Patrick Rothfuss&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Crossing to Safety&lt;/em&gt;&lt;/strong&gt; by Wallace Stegner&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;music&quot;&gt;&lt;a href=&quot;#music&quot; aria-label=&quot;music permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Music&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Neko Case — Hell-On &lt;br&gt;📝 &lt;em&gt;Pretty much all Neko Case ever is ​💯​ (Fox Confessor is my fave), but her new album is great.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Avett Brothers&lt;/li&gt;
&lt;li&gt;The Mountain Goats — Sunset Tree&lt;/li&gt;
&lt;li&gt;Clare and the Reasons — Alphabet City&lt;/li&gt;
&lt;li&gt;Granddaddy&lt;/li&gt;
&lt;li&gt;Beach House — Bloom&lt;/li&gt;
&lt;li&gt;Hayden — Skyscraper National Park&lt;/li&gt;
&lt;li&gt;Andrew Bird — Armchair Apocrypha&lt;/li&gt;
&lt;li&gt;Lucius — Wildewoman&lt;/li&gt;
&lt;li&gt;Midlake — The Trials of Van Occupanther&lt;/li&gt;
&lt;li&gt;Lewis &amp;#x26; Clarke — Bare Bones and Branches&lt;/li&gt;
&lt;li&gt;Nada Surf&lt;/li&gt;
&lt;li&gt;Eels — Blinking Lights&lt;/li&gt;
&lt;li&gt;Manchester Orchestra — Hope&lt;/li&gt;
&lt;li&gt;TV on the Radio&lt;/li&gt;
&lt;li&gt;John Vanderslice — Pixel Revolt&lt;/li&gt;
&lt;li&gt;The Long Winters — The Worst You Can Do is Harm&lt;/li&gt;
&lt;li&gt;Josh Ritter — Sermon on the Rocks&lt;/li&gt;
&lt;li&gt;Stephen Malkmus — self titled&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ZXu6q-6JKjA&quot;&gt;Alvvays&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dirty Computer — Janelle Monae&lt;/li&gt;
&lt;li&gt;Staying at Tamara’s — George Ezra&lt;/li&gt;
&lt;li&gt;What is Love? — Clean Bandit&lt;/li&gt;
&lt;li&gt;Inside Llewyn Davis Soundtrack&lt;/li&gt;
&lt;li&gt;The Punch Brothers&lt;/li&gt;
&lt;li&gt;Love - Alone Again Or&lt;/li&gt;
&lt;li&gt;Durand Jones &amp;#x26; The Indications - Smile&lt;/li&gt;
&lt;li&gt;Willie Nelson &amp;#x26; Merle Haggard - Pancho and Lefty&lt;/li&gt;
&lt;li&gt;Chance the Rapper - Same Drugs&lt;/li&gt;
&lt;li&gt;Fountains of Wayne - any album, but especially &lt;em&gt;Utopia Parkway&lt;/em&gt; &lt;br&gt;📝 &lt;em&gt;YES&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Dear Evan Hansen&lt;/em&gt; original broadway cast recording&lt;/li&gt;
&lt;li&gt;Fall Out Boy - the song &lt;em&gt;Young Volcanoes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Years &amp;#x26; Years - the song &lt;em&gt;If You’re Over Me&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Kenny Loggins - the song &lt;em&gt;Footloose&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Carly Rae Jepsen - &lt;em&gt;Emotion&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Angels and Airwaves - the song &lt;em&gt;The Gift&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Tame Impala&lt;/li&gt;
&lt;li&gt;Rameses B - Spacewalk and Spacewalk II&lt;/li&gt;
&lt;li&gt;Bomba Estéreo - &lt;em&gt;Ayo (esp. ‘Duele’)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Lizzo&lt;/li&gt;
&lt;li&gt;Duvet - While (True) 😉&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.talesoftheforgotten.net/&quot;&gt;Tales of the Forgotten&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The xx&lt;/li&gt;
&lt;li&gt;Sylvan Esso - Die Young&lt;/li&gt;
&lt;li&gt;MISSIO - Bottom of the Deep Blue Sea&lt;/li&gt;
&lt;li&gt;LCD Soundsystem&lt;/li&gt;
&lt;li&gt;Bishop Briggs&lt;/li&gt;
&lt;li&gt;NIN - Only&lt;/li&gt;
&lt;li&gt;Trent Reznor + David Bowie - Afraid of Americans&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=mAKsZ26SabQ&quot;&gt;TWICE - Yes or Yes&lt;/a&gt; (Kpop)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;podcasts&quot;&gt;&lt;a href=&quot;#podcasts&quot; aria-label=&quot;podcasts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Podcasts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Song Exploder &lt;br&gt;📝 &lt;em&gt;(really loved the Fleetwood Mac one)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://armchairexpertpod.com/&quot;&gt;Armchair Expert&lt;/a&gt; with Dax Shepard&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nbc.com/the-good-place/exclusives/tgp-podcast&quot;&gt;The Good Place&lt;/a&gt; podcast with Marc Evan Jackson &lt;br&gt;📝 &lt;em&gt;+1&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://soundcloud.com/theanthropocenereviewed&quot;&gt;The Anthropocene Reviewed&lt;/a&gt; with John Green&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=5im6jbhaRhw&quot;&gt;MBMBAM&lt;/a&gt; &lt;br&gt;📝 &lt;em&gt;Start with the latest episodes! It’s really best at around ep 300. Also do yourself a favor and watch the video I linked here because it’s *chefs kiss*&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.stitcher.com/podcast/history-chicks/the-history-chicks&quot;&gt;The History Chicks&lt;/a&gt; &lt;br&gt;📝 &lt;em&gt;This is a BRILLIANT podcast hosted by 2 women who talk about women in history.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rss.art19.com/conan-obrien&quot;&gt;Conan O’Brien Needs a Friend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://feeds.feedburner.com/boom-time-flula&quot;&gt;Boom Time with Fula Borg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rss.art19.com/my-favorite-murder-with-karen-kilgariff-and-georgia-hardstark-fb&quot;&gt;My Favorite Murder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Homecoming&lt;/li&gt;
&lt;li&gt;Bubble&lt;/li&gt;
&lt;li&gt;The Moth&lt;/li&gt;
&lt;li&gt;The Adventure Zone&lt;/li&gt;
&lt;li&gt;Habitat&lt;/li&gt;
&lt;li&gt;The Mad Fientist&lt;/li&gt;
&lt;li&gt;Absolute Worst Podcast&lt;/li&gt;
&lt;li&gt;Pivot with Kara Swisher and Scott Galloway&lt;/li&gt;
&lt;li&gt;Techmeme Drive Home&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;board-games&quot;&gt;&lt;a href=&quot;#board-games&quot; aria-label=&quot;board games permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Board Games&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://geekdad.com/2017/11/5-minute-dungeon-review/&quot;&gt;5 Minute Dungeon&lt;/a&gt; &lt;br&gt;📝 &lt;em&gt;A cooperative game where you throw down cards together to complete certain goals (three of one type of card, etc) together and fight battles.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Dropmix &lt;br&gt;📝 &lt;em&gt;It’s like Uno and Guitar Hero had a baby. ​​This is super fun to just have running at a party. Lots of fun and laughter.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Lords-Waterdeep-Dungeons-Dragons-Board/dp/0786959916&quot;&gt;Lords of Waterdeep&lt;/a&gt; &lt;br&gt;📝 &lt;em&gt;LoW is the best&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Dominion-2nd-Edition-Board-Game/dp/B01LYLIS2U&quot;&gt;Dominion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Pandemic (co-op game) &lt;br&gt;📝 &lt;em&gt;Depending on which version you buy, it’s sort of a dice rolling game where you’re trying to stop the spread of disease with your teammates. It’s you against the game! TO SAVE THE WORLD&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Scythe&lt;/li&gt;
&lt;li&gt;Hanabi&lt;/li&gt;
&lt;li&gt;Forbidden Island (great with kids)&lt;/li&gt;
&lt;li&gt;Boss Monster&lt;/li&gt;
&lt;li&gt;Star Realms&lt;/li&gt;
&lt;li&gt;Bang!&lt;/li&gt;
&lt;li&gt;Terraforming Mars&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;video-games&quot;&gt;&lt;a href=&quot;#video-games&quot; aria-label=&quot;video games permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Video Games&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Hearthstone &lt;br&gt;📝 &lt;em&gt;F2P Warcraft-themed CCG. Super fun, casual game.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Stardew Valley 😜&lt;/li&gt;
&lt;li&gt;Undertale&lt;/li&gt;
&lt;li&gt;Gone Home&lt;/li&gt;
&lt;li&gt;Beat Saber&lt;/li&gt;
&lt;li&gt;Jazzpunk ​​&lt;br&gt;📝 &lt;em&gt;It’s a silly nonsense game. Basically all about finding strange easter-egg-type jokes all over the place&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Firewatch&lt;/li&gt;
&lt;li&gt;Donut County 🍩&lt;/li&gt;
&lt;li&gt;Stanley Parable&lt;/li&gt;
&lt;li&gt;Overcooked (fun co-op!)&lt;/li&gt;
&lt;li&gt;Spiderman 2018 (PS4)&lt;/li&gt;
&lt;li&gt;Divinity Original Sin 2 (best spouse co-op rpg) &lt;br&gt;📝 &lt;em&gt;+1&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Return of the Obra Dinn (Fritzy’s Game of the Year)&lt;/li&gt;
&lt;li&gt;Life is Strange&lt;/li&gt;
&lt;li&gt;FTL&lt;/li&gt;
&lt;li&gt;Red Dead Redemption 2&lt;/li&gt;
&lt;li&gt;Haque (roguelike with pets)&lt;/li&gt;
&lt;li&gt;Into the Breach&lt;/li&gt;
&lt;li&gt;Minit&lt;/li&gt;
&lt;li&gt;Celeste&lt;/li&gt;
&lt;li&gt;Tetris Effect (Switch)&lt;/li&gt;
&lt;li&gt;Disgaea 5 (systems on systems on systems)&lt;/li&gt;
&lt;li&gt;Assassin’s Creed Odyssey&lt;/li&gt;
&lt;li&gt;Xenoblade Chronicles 1 and 2 (epic jrpg fantasy timesink)&lt;/li&gt;
&lt;li&gt;Metroid: Samus Returns (3DS)&lt;/li&gt;
&lt;li&gt;Portal (1 and 2)&lt;/li&gt;
&lt;li&gt;Hotline Miami (violent)&lt;/li&gt;
&lt;li&gt;Civilization V (great co-op)&lt;/li&gt;
&lt;li&gt;holedown (iOS)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;newsletters&quot;&gt;&lt;a href=&quot;#newsletters&quot; aria-label=&quot;newsletters permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Newsletters&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://link.mail.bloombergbusiness.com/join/4wm/moneystuff-signup?source=msweb&quot;&gt;Money Stuff&lt;/a&gt; &lt;br&gt;📝 &lt;em&gt;This is one of the funniest and most educational newsletters I have ever read&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nowiknow.com/&quot;&gt;Now I Know&lt;/a&gt; by Dan Lewis&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;youtube-channels&quot;&gt;&lt;a href=&quot;#youtube-channels&quot; aria-label=&quot;youtube channels permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;YouTube channels&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCF1fG3gT44nGTPU2sVLoFWg&quot;&gt;Patrick H Willems&lt;/a&gt; (film essays)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCJkMlOu7faDgqh4PfzbpLdg&quot;&gt;The Nerdwriter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCHiwtz2tCEfS17N9A-WoSSw&quot;&gt;Pop Culture Detective&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCjFqcJQXGZ6T6sxyFB-5i6A&quot;&gt;Every Frame a Painting&lt;/a&gt; (oldie but goodie)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCmQThz1OLYt8mb2PU540LOA&quot;&gt;The Art Assignment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCG1h-Wqjtwz7uUANw6gazRw&quot;&gt;Lindsay Ellis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/feed/subscriptions/UCE31MqUy6nIMJ_f8y4R3_AA&quot;&gt;Gavin Webber&lt;/a&gt; (HE MAKES CHEESE AND HE’S ADORABLE)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/user/numberphile&quot;&gt;Numberphile&lt;/a&gt; (Interesting math concepts)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/user/mattymatt&quot;&gt;Matt Baume&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/user/pushinguproses&quot;&gt;Pushinguproses&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;movies&quot;&gt;&lt;a href=&quot;#movies&quot; aria-label=&quot;movies permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Movies&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Searching (2018)&lt;/li&gt;
&lt;li&gt;Crazy Rich Asians (2018)&lt;/li&gt;
&lt;li&gt;Eighth Grade (2018) ​​&lt;br&gt;📝 &lt;em&gt;This was amazing. it feels like it should be required watching for anyone with a kid in junior high or soon to be in junior high.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;John Mulaney’s Kid Gorgeous special on Netflix (2018)&lt;/li&gt;
&lt;li&gt;BlacKkKlansman (2018)&lt;/li&gt;
&lt;li&gt;Ghost Dog: The Way of the Samurai (1999)&lt;/li&gt;
&lt;li&gt;Top Secret! (1984)&lt;/li&gt;
&lt;li&gt;Cool Hand Luke (1967)&lt;/li&gt;
&lt;li&gt;Big Night (1996)&lt;/li&gt;
&lt;li&gt;Ocean&apos;s 8 (2018)&lt;/li&gt;
&lt;li&gt;Love, Simon (2018)&lt;/li&gt;
&lt;li&gt;A Quiet Place (2018)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=xJWLxxD0Hp8&quot;&gt;Anything from Ghibli&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Roma (2018)&lt;/li&gt;
&lt;li&gt;A Quiet Place (2018)&lt;/li&gt;
&lt;li&gt;The Night Before (2015)&lt;/li&gt;
&lt;li&gt;Trading Places (1983)&lt;/li&gt;
&lt;li&gt;It (2017)&lt;/li&gt;
&lt;li&gt;Game of Death (1978)&lt;/li&gt;
&lt;li&gt;Arrival (2016)&lt;/li&gt;
&lt;li&gt;Meru (Documentary) (2015)&lt;/li&gt;
&lt;li&gt;Moneyball (2011)&lt;/li&gt;
&lt;li&gt;Dunkirk (2017)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;tv-shows&quot;&gt;&lt;a href=&quot;#tv-shows&quot; aria-label=&quot;tv shows permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;TV Shows&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The Good Place&lt;/li&gt;
&lt;li&gt;Fresh Off The Boat&lt;/li&gt;
&lt;li&gt;Top Chef&lt;/li&gt;
&lt;li&gt;Crazy Ex-Girlfriend&lt;/li&gt;
&lt;li&gt;Mindhunter&lt;/li&gt;
&lt;li&gt;Stranger Things&lt;/li&gt;
&lt;li&gt;Bob’s Burgers&lt;/li&gt;
&lt;li&gt;Justified&lt;/li&gt;
&lt;li&gt;The Marvelous Mrs. Maisel &lt;br&gt;📝 &lt;em&gt;SO GOOD. ​​I wish I could eat this show.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The Adventures of Brisco County Jr.&lt;/li&gt;
&lt;li&gt;Harmon Quest&lt;/li&gt;
&lt;li&gt;Big Mouth &lt;br&gt;📝 &lt;em&gt;+1&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Salt Fat Acid Heat&lt;/li&gt;
&lt;li&gt;Black Mirror&lt;/li&gt;
&lt;li&gt;Homecoming&lt;/li&gt;
&lt;li&gt;Doctor Who (Season 11)&lt;/li&gt;
&lt;li&gt;Maniac&lt;/li&gt;
&lt;li&gt;Fargo&lt;/li&gt;
&lt;li&gt;Superstore&lt;/li&gt;
&lt;li&gt;Nightflyers&lt;/li&gt;
&lt;li&gt;The Expanse &lt;br&gt;📝 &lt;em&gt;+1&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Wild Wild Country (documentary series)&lt;/li&gt;
&lt;li&gt;It’s Always Sunny in Philadelphia Season 13 Finale&lt;/li&gt;
&lt;li&gt;Patriot&lt;/li&gt;
&lt;li&gt;Succession&lt;/li&gt;
&lt;li&gt;Billions&lt;/li&gt;
&lt;li&gt;Atlanta&lt;/li&gt;
&lt;li&gt;The Durrells in Corfu&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.netflix.com/title/80195811&quot;&gt;Churchill’s Secret Agents: The New Recruits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Last Kingdom (Netflix series)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.netflix.com/title/70202589&quot;&gt;Sherlock&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;food&quot;&gt;&lt;a href=&quot;#food&quot; aria-label=&quot;food permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Food&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Darrell Lea soft eating licorice &lt;br&gt;📝 &lt;em&gt;YES&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Angie’s BOOMCHICKAPOP Sweet and Salty Kettle Corn&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Inglehoffer-Mustard-Creamy-Dill-Ounce/dp/B004EI4DVG/ref=asc_df_B004EI4DVG/?tag=hyprod-20&amp;#x26;linkCode=df0&amp;#x26;hvadid=312191712419&amp;#x26;hvpos=1o4&amp;#x26;hvnetw=g&amp;#x26;hvrand=8575404760498172754&amp;#x26;hvpone=&amp;#x26;hvptwo=&amp;#x26;hvqmt=&amp;#x26;hvdev=c&amp;#x26;hvdvcmdl=&amp;#x26;hvlocint=&amp;#x26;hvlocphy=9029997&amp;#x26;hvtargid=pla-569494461283&amp;#x26;th=1&quot;&gt;Inglehoffer creamy dill mustard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Tropical flavored Sour Patch Kids&lt;/li&gt;
&lt;li&gt;Candy cane chill blizzard from Dairy Queen&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Cello-Whisps-Parmesan-Cheese-Crisp/dp/B01B5EF0OK/ref=asc_df_B01B5EF0OK/?tag=hyprod-20&amp;#x26;linkCode=df0&amp;#x26;hvadid=198091263277&amp;#x26;hvpos=1o1&amp;#x26;hvnetw=g&amp;#x26;hvrand=16644658852143123182&amp;#x26;hvpone=&amp;#x26;hvptwo=&amp;#x26;hvqmt=&amp;#x26;hvdev=c&amp;#x26;hvdvcmdl=&amp;#x26;hvlocint=&amp;#x26;hvlocphy=9033824&amp;#x26;hvtargid=pla-379871663170&amp;#x26;th=1&quot;&gt;Cello Whisps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Those giant candy cane sticks that you can only find at the dollar store for some reason&lt;/li&gt;
&lt;li&gt;Fried cheese with a sunny-side up egg in the middle&lt;/li&gt;
&lt;li&gt;Bone marrow&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tonyschocolonely.com/us/en//&quot;&gt;Tony’s Chocoloney&lt;/a&gt; - Milk Chocolate&lt;/li&gt;
&lt;li&gt;yesplz.coffee&lt;/li&gt;
&lt;li&gt;Tonkotsu Ramen from Ramen Tatsu-ya in Austin, TX if you’re ever there. It’s one of the most delectable things I&apos;ve ever had&lt;/li&gt;
&lt;li&gt;Sarah’s homemade from-scratch ramen 💯&lt;/li&gt;
&lt;li&gt;Maultasche (german dumplings), they’re delicious&lt;/li&gt;
&lt;li&gt;Creme Brulee donuts&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;recipes&quot;&gt;&lt;a href=&quot;#recipes&quot; aria-label=&quot;recipes permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Recipes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lynnandtonicblog.com/2010/04/02/party-dip/&quot;&gt;Party chip dip&lt;/a&gt; I make that is :chef-kisses-fingers:&lt;/li&gt;
&lt;li&gt;I made these &lt;a href=&quot;https://www.buzzfeed.com/michelleno/sugar-cookies-icing-baking-tips&quot;&gt;Buzzfeed sugar cookies&lt;/a&gt; this year and they were pretty good &lt;br&gt;📝 &lt;em&gt;​​I made them too and +1 to this recipe!&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.marthastewart.com/340315/one-bowl-chocolate-cake?czone=food/chocolate-center/chocolate-recipes&amp;#x26;gallery=874542&amp;#x26;slide=340315&amp;#x26;center=874882&quot;&gt;Chocolate Cake&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.foodonpaper.com/2012/02/flourless-orange-and-almond-cake.html&quot;&gt;GF Almond Cake&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.thedefineddish.com/whole30-spaghetti-squash-pad-thai/&quot;&gt;Spaghetti Squash Pad Thai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://thepioneerwoman.com/cooking/monkey-bread/&quot;&gt;Monkey Bread (super easy!)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://kindredcocktails.com/cocktail/bittenbender&quot;&gt;Bittenbender&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;drinks&quot;&gt;&lt;a href=&quot;#drinks&quot; aria-label=&quot;drinks permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Drinks&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Diet Dr. Pepper&lt;/li&gt;
&lt;li&gt;Rekorderlig pear cider (very sweet, but amaaazing)&lt;/li&gt;
&lt;li&gt;Col Solare Cabernet Sauvignon 2014&lt;/li&gt;
&lt;li&gt;Weller 107 Antique &lt;br&gt;📝 &lt;em&gt;​​Best bourbon for the money hands down.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Hot Water &lt;br&gt;📝 &lt;em&gt;+1&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Hot Water with Lemon!&lt;/li&gt;
&lt;li&gt;Buffalo Trace Burbon&lt;/li&gt;
&lt;li&gt;Kusmi Imperial Label Green Tea&lt;/li&gt;
&lt;li&gt;Spindrift sparkling water (esp. mixed with Tart Cherry juice)&lt;/li&gt;
&lt;li&gt;Blue Lotus Chai (it comes with a tiny wooden spoon)&lt;/li&gt;
&lt;li&gt;Reed’s Extra Ginger Brew&lt;/li&gt;
&lt;li&gt;I went to the &lt;a href=&quot;https://docs.google.com/spreadsheets/d/1EbFOAuGNRT3gq_jWAnd1VeXlYyvv0op1YHCy6IgpjLI/edit#gid=0&quot;&gt;Schilling Cider House in Seattle&lt;/a&gt; and had all the best ciders I’ve ever had&lt;/li&gt;
&lt;li&gt;Sugar-free Red Bull&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Peek inside our home office setups]]></title><description><![CDATA[Ever wonder what other people’s home office setups are like? Well my friend, wonder no more. (Okay, you can wonder a little. These are only…]]></description><link>https://blog.andyet.com/2018/07/31/peek-inside-our-home-office-setups/</link><guid isPermaLink="false">https://blog.andyet.com/2018/07/31/peek-inside-our-home-office-setups/</guid><pubDate>Tue, 31 Jul 2018 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Ever wonder what other people’s home office setups are like? Well my friend, wonder no more. (Okay, you can wonder a little. These are only the setups of a couple of people on our team, which probably do not represent the entirety of the human experience. But anyway. Enjoy.)&lt;/p&gt;
&lt;h2 id=&quot;where-do-you-work&quot;&gt;&lt;a href=&quot;#where-do-you-work&quot; aria-label=&quot;where do you work permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Where do you work?&lt;/h2&gt;
&lt;h3 id=&quot;luke-karrys-senior-developer&quot;&gt;&lt;a href=&quot;#luke-karrys-senior-developer&quot; aria-label=&quot;luke karrys senior developer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Luke Karrys, Senior developer&lt;/h3&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6a178744b1855548cadd660d51e762d4/a2510/2018-office-setup-luke.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 74.8344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIFAwT/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAABdJ+c1QOEP//EABoQAAICAwAAAAAAAAAAAAAAAAECACEQERL/2gAIAQEAAQUCWmYcYY6JivX/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAYEAADAQEAAAAAAAAAAAAAAAAAEDERMv/aAAgBAQAGPwKnVWqn/8QAHBAAAwACAwEAAAAAAAAAAAAAAAERIUExUWGh/9oACAEBAAE/Icx7XFLo6NfbE86v0va+mqx//9oADAMBAAIAAwAAABBQD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABURAQEAAAAAAAAAAAAAAAAAABAh/9oACAECAQE/EKf/xAAbEAEAAwEAAwAAAAAAAAAAAAABABEhMVFhcf/aAAgBAQABPxC7uKPShWfbiURLEb5rypQpbWDuwgNHbdgdOD46iYADVT//2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Luke&apos;s Desk&quot;
        title=&quot;&quot;
        src=&quot;/static/6a178744b1855548cadd660d51e762d4/3cb18/2018-office-setup-luke.jpg&quot;
        srcset=&quot;/static/6a178744b1855548cadd660d51e762d4/0a254/2018-office-setup-luke.jpg 151w,
/static/6a178744b1855548cadd660d51e762d4/c8fe0/2018-office-setup-luke.jpg 303w,
/static/6a178744b1855548cadd660d51e762d4/3cb18/2018-office-setup-luke.jpg 605w,
/static/6a178744b1855548cadd660d51e762d4/39048/2018-office-setup-luke.jpg 908w,
/static/6a178744b1855548cadd660d51e762d4/a2510/2018-office-setup-luke.jpg 1000w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I work from a spare bedroom in my house. I also spend the very occasional afternoon working from a nearby coffee shop, but most of the time I prefer to work from the same spot every day. My home office only locks from the outside which means sometimes I have a system where I lock myself in to deter my 3 year old from busting in &lt;a href=&quot;https://youtu.be/Mh4f9AYRCZY&quot;&gt;BBC style&lt;/a&gt;. Then I text my wife at the end of the day to let me out.&lt;/p&gt;
&lt;h3 id=&quot;kate-farrar-designer-developer&quot;&gt;&lt;a href=&quot;#kate-farrar-designer-developer&quot; aria-label=&quot;kate farrar designer developer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Kate Farrar, Designer, Developer&lt;/h3&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d0172c3c43617c7352715744d04ad33a/a2510/2018-office-setup-kate.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 70.19867549668875%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFA//EABUBAQEAAAAAAAAAAAAAAAAAAAID/9oADAMBAAIQAxAAAAFlLECpE8pP/8QAGxAAAgMAAwAAAAAAAAAAAAAAAQIAAxIREyH/2gAIAQEAAQUCPOe/xCch2hlduF//xAAWEQADAAAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8BdZD/xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQIBAT8BwJ//xAAaEAACAwEBAAAAAAAAAAAAAAAAEQExQSGh/9oACAEBAAY/AnhRwWF+CmGf/8QAGxAAAgMBAQEAAAAAAAAAAAAAAREAITFBYZH/2gAIAQEAAT8hyQU0zsv2EBRQi5p6Yb6zEURkPez/2gAMAwEAAgADAAAAEK8v/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAEDAQE/EFCtv//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAgJl//xAAcEAEBAAMBAAMAAAAAAAAAAAABEQAhMVFBgaH/2gAIAQEAAT8QmgdohNfGUh72TvFYdu33KLeC7H6sw7RNgQYsgJDZDz8z/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Kate&apos;s Desk&quot;
        title=&quot;&quot;
        src=&quot;/static/d0172c3c43617c7352715744d04ad33a/3cb18/2018-office-setup-kate.jpg&quot;
        srcset=&quot;/static/d0172c3c43617c7352715744d04ad33a/0a254/2018-office-setup-kate.jpg 151w,
/static/d0172c3c43617c7352715744d04ad33a/c8fe0/2018-office-setup-kate.jpg 303w,
/static/d0172c3c43617c7352715744d04ad33a/3cb18/2018-office-setup-kate.jpg 605w,
/static/d0172c3c43617c7352715744d04ad33a/39048/2018-office-setup-kate.jpg 908w,
/static/d0172c3c43617c7352715744d04ad33a/a2510/2018-office-setup-kate.jpg 1000w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I have an extra bedroom in my house that I use as an office. At my old apartment I used to work in my living room, and I’ve found that being able to close the door and walk away at the end of the day is really nice. Having a separate space has been great for me!&lt;/p&gt;
&lt;h3 id=&quot;diana-perkins-designer-developer&quot;&gt;&lt;a href=&quot;#diana-perkins-designer-developer&quot; aria-label=&quot;diana perkins designer developer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Diana Perkins, Designer, Developer&lt;/h3&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b542cd5087b47e11dbecebf5e3597b4d/a2510/2018-office-setup-diana.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 65.56291390728477%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAUCAwT/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAASqa1WZkMv/EABsQAAIDAAMAAAAAAAAAAAAAAAECAAMSEyIz/9oACAEBAAEFAmsO2cTkUxO8uOXp8//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/AWf/xAAXEQADAQAAAAAAAAAAAAAAAAABAhBB/9oACAECAQE/AQ2T/8QAGhAAAgMBAQAAAAAAAAAAAAAAAAECESExEP/aAAgBAQAGPwLXhkrOjscVzz//xAAaEAACAwEBAAAAAAAAAAAAAAAAAREhMUGh/9oACAEBAAE/IcOUdOWDvILCQY2UY/o//9oADAMBAAIAAwAAABB4z//EABcRAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQMBAT8QTbSH/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERIf/aAAgBAgEBPxDJwM//xAAcEAEBAAICAwAAAAAAAAAAAAABEQAhUcExQYH/2gAIAQEAAT8QsjOvEmsQoai0541iMLNMFjkggD6xbBAHzIB5T11n/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Diana&apos;s Desk&quot;
        title=&quot;&quot;
        src=&quot;/static/b542cd5087b47e11dbecebf5e3597b4d/3cb18/2018-office-setup-diana.jpg&quot;
        srcset=&quot;/static/b542cd5087b47e11dbecebf5e3597b4d/0a254/2018-office-setup-diana.jpg 151w,
/static/b542cd5087b47e11dbecebf5e3597b4d/c8fe0/2018-office-setup-diana.jpg 303w,
/static/b542cd5087b47e11dbecebf5e3597b4d/3cb18/2018-office-setup-diana.jpg 605w,
/static/b542cd5087b47e11dbecebf5e3597b4d/39048/2018-office-setup-diana.jpg 908w,
/static/b542cd5087b47e11dbecebf5e3597b4d/a2510/2018-office-setup-diana.jpg 1000w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I have a separate office in my house. It was a necessity that we purchase a home with three bedrooms: one to sleep in, one for my home office, and one for my husband&apos;s home office.&lt;/p&gt;
&lt;h3 id=&quot;heather-young-devops-engineer&quot;&gt;&lt;a href=&quot;#heather-young-devops-engineer&quot; aria-label=&quot;heather young devops engineer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heather Young, Dev/Ops engineer&lt;/h3&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1f6976534e7ec681a946f6d0f8d8801f/a2510/2018-office-setup-heather.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 74.8344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABAACBf/EABYBAQEBAAAAAAAAAAAAAAAAAAIBA//aAAwDAQACEAMQAAAB6ZtDzbYEb//EABkQAQEAAwEAAAAAAAAAAAAAAAEAAgMRFP/aAAgBAQABBQKNplD2zZePo13/xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8BZH//xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAIAQIBAT8Bq6//xAAaEAADAQADAAAAAAAAAAAAAAAAAREhAlFx/9oACAEBAAY/Ahw6NVKuLXhtP//EABoQAQACAwEAAAAAAAAAAAAAAAEAESFBUYH/2gAIAQEAAT8hmyaIIt8MCw6IeIjbYzO4PKn/2gAMAwEAAgADAAAAEPvv/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAERUWH/2gAIAQMBAT8QhWaH/8QAFxEAAwEAAAAAAAAAAAAAAAAAABEhYf/aAAgBAgEBPxBrDI//xAAcEAEBAAICAwAAAAAAAAAAAAABEQAxIUFRsdH/2gAIAQEAAT8QYCuFsLtDvJsVU0O8GloRycRPuRw4ER8JltG2r9Of/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Heather&apos;s Desk&quot;
        title=&quot;&quot;
        src=&quot;/static/1f6976534e7ec681a946f6d0f8d8801f/3cb18/2018-office-setup-heather.jpg&quot;
        srcset=&quot;/static/1f6976534e7ec681a946f6d0f8d8801f/0a254/2018-office-setup-heather.jpg 151w,
/static/1f6976534e7ec681a946f6d0f8d8801f/c8fe0/2018-office-setup-heather.jpg 303w,
/static/1f6976534e7ec681a946f6d0f8d8801f/3cb18/2018-office-setup-heather.jpg 605w,
/static/1f6976534e7ec681a946f6d0f8d8801f/39048/2018-office-setup-heather.jpg 908w,
/static/1f6976534e7ec681a946f6d0f8d8801f/a2510/2018-office-setup-heather.jpg 1000w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Home, one of many coffee shops, or a co-working space. I also travel alot so I work from coffee shops or other random spots pretty often.&lt;/p&gt;
&lt;h2 id=&quot;whats-your-hardware-setup&quot;&gt;&lt;a href=&quot;#whats-your-hardware-setup&quot; aria-label=&quot;whats your hardware setup permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’s your hardware setup?&lt;/h2&gt;
&lt;h3 id=&quot;diana&quot;&gt;&lt;a href=&quot;#diana&quot; aria-label=&quot;diana permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Diana&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.apple.com/shop/buy-mac/macbook-pro/13-inch-space-gray-2.3ghz-dual-core-256gb&quot;&gt;13&quot; MacBook Pro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.benq.dk/product/monitor/pd2700q&quot;&gt;27&quot; BenQ IPS Monitor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.logitech.com/en-us/product/mx-master-2s-flow&quot;&gt;Logitech MX Master 2S Mouse&lt;/a&gt;: I&apos;m big on assigning buttons to various tasks, and I&apos;m super into the horizontal thumb scroll wheel&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.apple.com/shop/buy-ipad/ipad-pro&quot;&gt;iPad Pro&lt;/a&gt;: for drawing and notes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;luke&quot;&gt;&lt;a href=&quot;#luke&quot; aria-label=&quot;luke permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Luke&lt;/h3&gt;
&lt;p&gt;I use a 2016 MacBook Pro that is in clamshell mode on my desk most of the time connected to an &lt;a href=&quot;https://www.apple.com/shop/product/HKN62LL/A/lg-ultrafine-5k-display&quot;&gt;LG 5k monitor&lt;/a&gt;. I also have a previous generation &lt;a href=&quot;https://www.amazon.com/Logitech-Master-Wireless-Mouse-High-precision/dp/B076VKQVK3&quot;&gt;Logitech MX Master mouse&lt;/a&gt; and a &lt;a href=&quot;https://www.amazon.com/Apple-Bluetooth-Wireless-Keyboard-MC184LL/dp/B002TMRZOQ&quot;&gt;previous generation Apple Wireless Keyboard&lt;/a&gt; (before they were &quot;magic&quot;) that I use because they&apos;re not broken, although I spend a lot of time looking at new keyboards and mice online.&lt;/p&gt;
&lt;h3 id=&quot;heather&quot;&gt;&lt;a href=&quot;#heather&quot; aria-label=&quot;heather permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heather&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Apple-Bluetooth-Wireless-Keyboard-MC184LL/dp/B002TMRZOQ&quot;&gt;Keyboard&lt;/a&gt;: Apple Wireless Bluetooth Keyboard&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.logitech.com/en-us/product/m720-triathlon&quot;&gt;Mouse&lt;/a&gt;: Logitech M720 Triathalon Multi­Device Wireless Mouse&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.kensington.com/us/us/7137/k98617ww/securetrek-156-laptop-backpack&quot;&gt;Backpack&lt;/a&gt;: I did a TON of research before buying this backpack and have been soooo happy. It’s roomy but not overly bulky. It’s built for security so has anti-slash fabric and a neat locking mechanism that locks the main zippers in place and prevents it from being opened when locked. It works with a &lt;a href=&quot;https://www.kensington.com/en/fi/v/4482/2707/microsaver-20-keyed-twin-laptop-lock&quot;&gt;dual-head cable lock&lt;/a&gt; that is also made by Kensington. It’s been handy for working in public spaces and I have a lot more peace of mind since I can secure my laptop and backpack at the same time if I need to leave for a bathroom break or something.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.maclocks.com/mac-cable-locks/mac-locks/the-ledge-new-macbook-pro-lock-macbook-pro-touch-bar-13-and-15-security-lock.html&quot;&gt;Ledge Lock Adapter from Maclocks&lt;/a&gt;: MacBooks aren’t made with Kensington locks but MacLocks makes a handy adapter called Ledge that mounts in the slot on the side. It’s pretty sturdy and would deter most thieves since you need a non-standard screwdriver to get it off.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.raindesigninc.com/mstand.html&quot;&gt;Raindesign mStand&lt;/a&gt;: This raises my laptop a little to prevent neck strain. I don’t use it all the time, but it’s effective.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.beatsbydre.com/headphones&quot;&gt;Beats Headphones&lt;/a&gt;: I don’t like these as much as the Bose ones that I used to have, but they are functional and have a nice travel case.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://oristand.co&quot;&gt;Oristand standing desk converter&lt;/a&gt;: Tragically, this company closed down their operation in December 2017. They made standing desk converters out of sturdy cardboard so they were super affordable. I’ve had this for over a year, and it’s still in great shape. It folds down to a flat piece of cardboard so I can store it away when it’s not in use.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;kate&quot;&gt;&lt;a href=&quot;#kate&quot; aria-label=&quot;kate permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Kate&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Rain-Design-mStand-Laptop-Patented/&quot;&gt;Rain Design mStand&lt;/a&gt;: I&apos;ve had this for 4 years now, and it still does it&apos;s job perfectly. Helps keep my laptop cool and also raises it to be level to my monitor.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.urbanears.com/ue_us_en/plattan-2-bluetooth&quot;&gt;Urbanears Plattan 2 Bluetooth Headphones&lt;/a&gt;: I&apos;ve been using Urbanears for almost 10 years now and I love them. Recently upgraded to the Plattan 2 Bluetooth headphones. They have 30 hours of listening time on one battery, plus I can plug them in using an aux cable. Great for music and calls.&lt;/li&gt;
&lt;li&gt;Post-its: I&apos;m a note taker and an obsessive doodler. I need post-its on hand for meetings and to jot things down or I forget everything.&lt;/li&gt;
&lt;li&gt;La Croix: Gotta stay hydrated - Pamplemousse is my favorite flavor.&lt;/li&gt;
&lt;li&gt;Toys: I have several Lego minifigs, three stress balls, and two Tech Decks on my desk to play with on calls and for little breaks.&lt;/li&gt;
&lt;li&gt;Inspirational/helpful Post-its: I have post-its on my monitor that include robot doodles, sketches, a Tie Fighter, and a list of CSS property orders that I put up there years ago and never took down :) These make my setup feel like home!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-are-your-software-programs-du-jour&quot;&gt;&lt;a href=&quot;#what-are-your-software-programs-du-jour&quot; aria-label=&quot;what are your software programs du jour permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What are your software programs du jour?&lt;/h2&gt;
&lt;h3 id=&quot;diana-1&quot;&gt;&lt;a href=&quot;#diana-1&quot; aria-label=&quot;diana 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Diana&lt;/h3&gt;
&lt;h4 id=&quot;the-obvious-ones&quot;&gt;&lt;a href=&quot;#the-obvious-ones&quot; aria-label=&quot;the obvious ones permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The obvious ones:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sketchapp.com/&quot;&gt;Sketch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sublimetext.com/&quot;&gt;Sublime Text&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://slack.com/&quot;&gt;Slack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.iterm2.com/&quot;&gt;iTerm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;the-not-obvious-ones&quot;&gt;&lt;a href=&quot;#the-not-obvious-ones&quot; aria-label=&quot;the not obvious ones permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The not-obvious ones:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://sipapp.io/&quot;&gt;Sip&lt;/a&gt;: a great little color picker with tons of options. It&apos;s great for switching what kind of color value you want copied to your clipboard, which makes switching between project types a breeze.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://itunes.apple.com/us/app/littleipsum/id405772121&quot;&gt;Little Ipsum&lt;/a&gt;: a lorem ipsum generator that lives in your taskbar and allows you to choose various lengths of text to copy to your clipboard with a single click.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://hocusfoc.us/&quot;&gt;Hocus Focus&lt;/a&gt;: hides inactive windows, which really helps me focus. You can also create various profiles and tune how long you want the app to be open on a per-app basis .&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://boostnote.io/&quot;&gt;Boostnote&lt;/a&gt;: nice little markdown editor.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://astropad.com/&quot;&gt;Astropad&lt;/a&gt;: while I do have a Cintiq, sometimes it&apos;s nice to use Astropad to connect to my iPad Pro instead. It&apos;s got a bit of lag, but it handles it super nicely in a very intuitive way.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;kate-1&quot;&gt;&lt;a href=&quot;#kate-1&quot; aria-label=&quot;kate 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Kate&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/useclear&quot;&gt;Clear&lt;/a&gt; for to-do lists&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://evernote.com&quot;&gt;Evernote&lt;/a&gt; for notes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sublimetext.com&quot;&gt;Sublime Text&lt;/a&gt; for code&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://spotify.com&quot;&gt;Spotify&lt;/a&gt; for tunes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;heather-1&quot;&gt;&lt;a href=&quot;#heather-1&quot; aria-label=&quot;heather 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heather&lt;/h3&gt;
&lt;h4 id=&quot;work-apps&quot;&gt;&lt;a href=&quot;#work-apps&quot; aria-label=&quot;work apps permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Work apps:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://xwavesoft.com/focus-matrix-for-iphone-ipad-mac.html&quot;&gt;Focus Matrix&lt;/a&gt;: Keeps me focused&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://justgetflux.com/&quot;&gt;Flux&lt;/a&gt;: Reduces blue light&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://backblaze.com/&quot;&gt;Backblaze&lt;/a&gt;: Keeps my machine backed up&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://iamfutureproof.com/tools/awareness/&quot;&gt;Awareness&lt;/a&gt;: Encourages me to take breaks&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.dejal.com/timeout/&quot;&gt;Time Out&lt;/a&gt;: A bit stricter than Awareness because it actually locks your computer up and grays the screen until you take a break&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://coffitivity.com/&quot;&gt;Coffitivity&lt;/a&gt;: Makes coffeeshop white noise&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://selfcontrolapp.com/&quot;&gt;SelfControl App&lt;/a&gt;: Blocks access to distracting websites&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;cooking-apps&quot;&gt;&lt;a href=&quot;#cooking-apps&quot; aria-label=&quot;cooking apps permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cooking apps:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.paprikaapp.com/&quot;&gt;Paprika Recipe Manager&lt;/a&gt;: Seriously the best!&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://recipe-gallery.com/&quot;&gt;RecipeGallery&lt;/a&gt;: OCR text recognition for photos of recipes from books or magazines&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;luke-1&quot;&gt;&lt;a href=&quot;#luke-1&quot; aria-label=&quot;luke 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Luke&lt;/h3&gt;
&lt;p&gt;The programs I use most often are &lt;a href=&quot;https://www.iterm2.com/&quot;&gt;iTerm 2&lt;/a&gt; and &lt;a href=&quot;https://www.sublimetext.com/3&quot;&gt;Sublime Text 3&lt;/a&gt; which I use for coding. They are both &lt;a href=&quot;https://github.com/lukekarrys/dotfiles&quot;&gt;very customized&lt;/a&gt; although it&apos;s in a Rube Goldberg fashion as I copied and pasted different bits from across the internet. I use &lt;a href=&quot;https://www.omnigroup.com/omnifocus&quot;&gt;Omnifocus&lt;/a&gt; for remembering to do stuff that I&apos;m supposed to do and &lt;a href=&quot;https://flexibits.com/fantastical&quot;&gt;Fantastical&lt;/a&gt; for remembering if I&apos;m supposed to be somewhere.&lt;/p&gt;
&lt;h2 id=&quot;whats-one-good-thing-you-try-to-practice-every-day&quot;&gt;&lt;a href=&quot;#whats-one-good-thing-you-try-to-practice-every-day&quot; aria-label=&quot;whats one good thing you try to practice every day permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’s one good thing you try to practice every day?&lt;/h2&gt;
&lt;h3 id=&quot;diana-2&quot;&gt;&lt;a href=&quot;#diana-2&quot; aria-label=&quot;diana 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Diana&lt;/h3&gt;
&lt;p&gt;I like to go outside during my lunch, or any time I need to think through a problem. For me, removing myself from my work area helps refresh my problem solving skills and energize me for the rest of the day.&lt;/p&gt;
&lt;h3 id=&quot;heather-2&quot;&gt;&lt;a href=&quot;#heather-2&quot; aria-label=&quot;heather 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heather&lt;/h3&gt;
&lt;p&gt;I try to switch posture every hour or so and sit as little as possible when I&apos;m not working. Using the &lt;a href=&quot;http://iamfutureproof.com/tools/awareness/&quot;&gt;Awareness&lt;/a&gt; app I mentioned helps to remind me to move around. When I&apos;m at lunch I try to stand a lot and I try to get a sweat-inducing workout in every day, even if it&apos;s only 10 minutes.&lt;/p&gt;
&lt;h3 id=&quot;luke-2&quot;&gt;&lt;a href=&quot;#luke-2&quot; aria-label=&quot;luke 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Luke&lt;/h3&gt;
&lt;p&gt;Every day I try to write down the things I would like to accomplish and what hours I would like to work in my &lt;a href=&quot;https://www.studioneat.com/products/panobook&quot;&gt;Studio Neat Panobook&lt;/a&gt;. This helps me keep what I&apos;m doing and what hours I keep as intentional as possible. I also do this way less often than I should, and it&apos;s immediately obvious at the end of most days when I don&apos;t do it.&lt;/p&gt;
&lt;h3 id=&quot;kate-2&quot;&gt;&lt;a href=&quot;#kate-2&quot; aria-label=&quot;kate 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Kate&lt;/h3&gt;
&lt;p&gt;Standing up every few hours! Sometimes I’ll go 5 hours without moving from my desk, which is not great. My Apple Watch reminds me to stand every hour so that helps.&lt;/p&gt;
&lt;h2 id=&quot;any-other-office-recommendations&quot;&gt;&lt;a href=&quot;#any-other-office-recommendations&quot; aria-label=&quot;any other office recommendations permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Any other office recommendations?&lt;/h2&gt;
&lt;h3 id=&quot;diana-3&quot;&gt;&lt;a href=&quot;#diana-3&quot; aria-label=&quot;diana 3 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Diana&lt;/h3&gt;
&lt;p&gt;I think this one is said often by people who work remotely, and it was a piece of advice I very much ignored until it became a problem for me: have a different area of your house where you work. Can I say it again? Have a different area of your house where you work. I used to sit all day and work at my computer, then eat dinner at my computer and play video games all night…at my computer. Both my productivity at work and my mental wellbeing at night suffered immensely; this is one piece of remote-work advice I don&apos;t recommend skipping. After separating my work / not-work areas, I&apos;ve been more focused during the day and more relaxed at night.&lt;/p&gt;
&lt;h3 id=&quot;heather-3&quot;&gt;&lt;a href=&quot;#heather-3&quot; aria-label=&quot;heather 3 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Heather&lt;/h3&gt;
&lt;p&gt;Working remotely is awesome, and often has the advantage of affording more freedom than an office environment. Often I find that my inner voice of judgement says that I should be more productive in a day or I need to be available at my desk every minute of every day, but psychology research suggests that a 5-minute break every hour can do wonders for one&apos;s productivity and health. Here&apos;s an &lt;a href=&quot;https://www.psychologytoday.com/us/blog/changepower/201704/how-do-work-breaks-help-your-brain-5-surprising-answers&quot;&gt;article&lt;/a&gt; with some great break ideas. Personally I&apos;ve found that short but regular breaks during the day helps me to reset my attention and makes me happier about life in general.&lt;/p&gt;
&lt;h3 id=&quot;luke-3&quot;&gt;&lt;a href=&quot;#luke-3&quot; aria-label=&quot;luke 3 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Luke&lt;/h3&gt;
&lt;p&gt;Working from home has been a huge positive in my life. At the same time it has provided many &quot;opportunities&quot; to find &quot;solutions&quot; to see what works best for me. And many of the solutions stopped working when I moved or had kids or changed roles. So my only recommendation would be to keep evaluating what works and what doesn&apos;t on your amazing remote work journey.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[SimpleWebRTC: Under the hood]]></title><description><![CDATA[The original SimpleWebRTC was one of the first Javascript libraries for WebRTC out there; the first public version was released more than…]]></description><link>https://blog.andyet.com/2018/07/25/simplewebrtc-under-the-hood/</link><guid isPermaLink="false">https://blog.andyet.com/2018/07/25/simplewebrtc-under-the-hood/</guid><pubDate>Wed, 25 Jul 2018 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/72623e0af6b89c3331ad69a8d05e0566/8e1fc/simplewebrtc_logo.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 24.50331125827815%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB35Cgf//EABUQAQEAAAAAAAAAAAAAAAAAAABB/9oACAEBAAEFAlf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAWEAADAAAAAAAAAAAAAAAAAAAAEDH/2gAIAQEABj8CKv/EABgQAQADAQAAAAAAAAAAAAAAAAEAEDFB/9oACAEBAAE/IXICdCv/2gAMAwEAAgADAAAAEHPP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGRABAAIDAAAAAAAAAAAAAAAAAQAREFFh/9oACAEBAAE/EBaBTpHlrQmP/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;SimpleWebRTC Logo&quot;
        title=&quot;&quot;
        src=&quot;/static/72623e0af6b89c3331ad69a8d05e0566/3cb18/simplewebrtc_logo.jpg&quot;
        srcset=&quot;/static/72623e0af6b89c3331ad69a8d05e0566/0a254/simplewebrtc_logo.jpg 151w,
/static/72623e0af6b89c3331ad69a8d05e0566/c8fe0/simplewebrtc_logo.jpg 303w,
/static/72623e0af6b89c3331ad69a8d05e0566/3cb18/simplewebrtc_logo.jpg 605w,
/static/72623e0af6b89c3331ad69a8d05e0566/8e1fc/simplewebrtc_logo.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The original SimpleWebRTC was one of the first Javascript libraries for WebRTC out there; the first public version was released more than five years ago. It offered a simple API that allowed JavaScript developers to prototype stuff quickly without having to understand the intricacies of the WebRTC APIs. “You can build cool stuff with WebRTC in five minutes” was true. Taking it to production at scale remains a bit more difficult.&lt;/p&gt;
&lt;p&gt;Under the hood, SimpleWebRTC consisted of a bunch of Javascript modules that let you access the camera, microphone, screen content, a wrapper for the RTCPeerConnection API, and something to keep track of your peers and do all of the signaling. It came with a very simple NodeJS signaling server called signalmaster. Socket.io was used for signaling.&lt;/p&gt;
&lt;p&gt;This simplicity came at a cost. SimpleWebRTC was designed for a single use-case: multiparty video chat using direct peer-to-peer connection between the participants. For the more complex problems we had to solve, we needed something better. Which is why we rewrote SimpleWebRTC &lt;a href=&quot;https://blog.andyet.com/2018/07/11/introducing-the-new-simplewebrtc&quot;&gt;almost from scratch&lt;/a&gt;, taking into account what we had learned in the last five years.&lt;/p&gt;
&lt;h2 id=&quot;goodbye-socketio-hello-stanzaio&quot;&gt;&lt;a href=&quot;#goodbye-socketio-hello-stanzaio&quot; aria-label=&quot;goodbye socketio hello stanzaio permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Goodbye socket.io, hello stanza.io&lt;/h2&gt;
&lt;p&gt;We moved from socket.io and a homegrown signaling protocol to Lance Stout’s stanza.io library which makes the XMPP protocol available with a nice Javascript API. This meant we did not have to reinvent concepts like “chat room” or “signaling” again but could use well-documented protocols instead, along with solid server implementations which have existed for more than a decade.&lt;/p&gt;
&lt;h2 id=&quot;less-of-a-javascript-stack-for-webrtc&quot;&gt;&lt;a href=&quot;#less-of-a-javascript-stack-for-webrtc&quot; aria-label=&quot;less of a javascript stack for webrtc permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Less of a Javascript stack for WebRTC&lt;/h2&gt;
&lt;p&gt;We had a quite elaborate Javascript stack for WebRTC. It did all kinds of fancy stuff, adding a node-style error-first API. We got rid of most of it since the W3C WebRTC API is pretty nice these days. Less code means less potential for errors.&lt;/p&gt;
&lt;h2 id=&quot;full-mesh-2018-style&quot;&gt;&lt;a href=&quot;#full-mesh-2018-style&quot; aria-label=&quot;full mesh 2018 style permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Full Mesh, 2018 style&lt;/h2&gt;
&lt;p&gt;The biggest problem of using full mesh, everyone sending directly to everyone else, has always been that both bandwidth and CPU requirements have grown linearly with the number of participants. Doing a call with more than four participants was hardly a good experience outside the lab. WebRTC implementations in 2018 are much more advanced than in 2012 and we take full advantage of that by adapting both video capture and bandwidth based on the number of participants.&lt;/p&gt;
&lt;p&gt;And yes, we have an SFU on the roadmap too. Because for really large groups you still need a server.&lt;/p&gt;
&lt;h2 id=&quot;fully-tested&quot;&gt;&lt;a href=&quot;#fully-tested&quot; aria-label=&quot;fully tested permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Fully tested&lt;/h2&gt;
&lt;p&gt;As we have seen &lt;a href=&quot;https://blog.andyet.com/2015/01/30/chrome-update-killed-the-webrtc-star&quot;&gt;in the past&lt;/a&gt; there can be changes in a new browser version. WebRTC is still changing quite a bit and in order to protect against this as well as the (much higher) chance of making a change that does not work as expected in all supported browsers we run a series of end-to-end tests.
Each of these tests verifies that the video flows in a number of different browser versions and combinations. This may sound simple but requires everything to go right under the hood. Some of them test more rare conditions such as the lack of a webcam.&lt;/p&gt;
&lt;p&gt;These tests run on our continuous integrations servers. Some run before and after every deploy, others every five minutes to test the service uptime and a larger set of tests is run each daily to catch changes in new browser versions. We combine this with &lt;a href=&quot;https://testrtc.com&quot;&gt;TestRTC&lt;/a&gt; for load testing to ensure the overall platform scales well.&lt;/p&gt;
&lt;p&gt;Expect a bit more detail in future blog posts. Until then, give the new &lt;a href=&quot;https://simplewebrtc.com&quot;&gt;SimpleWebRTC&lt;/a&gt; a try, and &lt;a href=&quot;https://andyet.com/contact&quot;&gt;let us know&lt;/a&gt; what you think.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Upgrade your style with &yet desktop wallpapers]]></title><description><![CDATA[One thing I've noticed since starting to work for &yet is how much pride everyone takes in the company; the employee love for &yet is…]]></description><link>https://blog.andyet.com/2018/07/17/upgrade-your-style-with-andyet-desktop-wallpapers/</link><guid isPermaLink="false">https://blog.andyet.com/2018/07/17/upgrade-your-style-with-andyet-desktop-wallpapers/</guid><pubDate>Tue, 17 Jul 2018 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/adb0240ae4e52a3f978c3cb2e2fbe491/8e1fc/wallpaper-andyet-software-color-thumb.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 62.251655629139066%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIE/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEE/9oADAMBAAIQAxAAAAHNcNMA/8QAGBAAAgMAAAAAAAAAAAAAAAAAAAECESD/2gAIAQEAAQUCJKs//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAIP/aAAgBAQAGPwJf/8QAFhABAQEAAAAAAAAAAAAAAAAAIQAg/9oACAEBAAE/IYbn/9oADAMBAAIAAwAAABAQL//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABkQAQADAQEAAAAAAAAAAAAAAAEQETEAUf/aAAgBAQABPxDh0N+lSq6rH//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Software is about people wallpaper&quot;
        title=&quot;&quot;
        src=&quot;/static/adb0240ae4e52a3f978c3cb2e2fbe491/3cb18/wallpaper-andyet-software-color-thumb.jpg&quot;
        srcset=&quot;/static/adb0240ae4e52a3f978c3cb2e2fbe491/0a254/wallpaper-andyet-software-color-thumb.jpg 151w,
/static/adb0240ae4e52a3f978c3cb2e2fbe491/c8fe0/wallpaper-andyet-software-color-thumb.jpg 303w,
/static/adb0240ae4e52a3f978c3cb2e2fbe491/3cb18/wallpaper-andyet-software-color-thumb.jpg 605w,
/static/adb0240ae4e52a3f978c3cb2e2fbe491/8e1fc/wallpaper-andyet-software-color-thumb.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One thing I&apos;ve noticed since starting to work for &amp;#x26;yet is how much pride everyone takes in the company; the employee love for &amp;#x26;yet is prominently on display, and it seems like everyone is repping at least one piece of &amp;#x26;yet swag at all times.&lt;/p&gt;
&lt;p&gt;Our very own &lt;a href=&quot;https://andyet.com/team/kate&quot;&gt;Kate&lt;/a&gt; took some time out of her busy schedule earlier this year and turned some of &lt;a href=&quot;https://andyet.com/team/amy&quot;&gt;Amy&apos;s&lt;/a&gt; work into some awesomely fun wallpapers for all of us at &amp;#x26;yet to enjoy. We have been absolutely loving them, and we figured it&apos;s about time to release them for everyone!&lt;/p&gt;
&lt;p&gt;From &lt;em&gt;Software is for People&lt;/em&gt; to the &lt;em&gt;&amp;#x26;yet yeti&lt;/em&gt;, please enjoy Kate’s awesome wallpaper collection.&lt;/p&gt;
&lt;h2 id=&quot;i-am-doing-this&quot;&gt;&lt;a href=&quot;#i-am-doing-this&quot; aria-label=&quot;i am doing this permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;I am doing this&lt;/h2&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 62.251655629139066%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHfnVQwK//EABcQAAMBAAAAAAAAAAAAAAAAAAABAiD/2gAIAQEAAQUCIpvP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFxAAAwEAAAAAAAAAAAAAAAAAAAERIP/aAAgBAQAGPwIdUz//xAAXEAEAAwAAAAAAAAAAAAAAAAABACAx/9oACAEBAAE/IYjgNf/aAAwDAQACAAMAAAAQ2A//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEAAgMAAAAAAAAAAAAAAAABEBEAIUH/2gAIAQEAAT8QwFXSL7IVcf/Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;I am doing this wallpaper&quot;
        title=&quot;&quot;
        src=&quot;/static/42676f368b9612c2a417e77734f9e58a/3cb18/wallpaper-andyet-doing-this-thumb.jpg&quot;
        srcset=&quot;/static/42676f368b9612c2a417e77734f9e58a/0a254/wallpaper-andyet-doing-this-thumb.jpg 151w,
/static/42676f368b9612c2a417e77734f9e58a/c8fe0/wallpaper-andyet-doing-this-thumb.jpg 303w,
/static/42676f368b9612c2a417e77734f9e58a/3cb18/wallpaper-andyet-doing-this-thumb.jpg 605w,
/static/42676f368b9612c2a417e77734f9e58a/8e1fc/wallpaper-andyet-doing-this-thumb.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;a href=&quot;/uploads/wallpaper-andyet-doing-this.jpg&quot;&gt;Get this wallpaper&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;hearts&quot;&gt;&lt;a href=&quot;#hearts&quot; aria-label=&quot;hearts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hearts&lt;/h2&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 62.251655629139066%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAd+dUMA//8QAFxABAAMAAAAAAAAAAAAAAAAAAgASIP/aAAgBAQABBQKBWz//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAYEAACAwAAAAAAAAAAAAAAAAAAAREgIf/aAAgBAQAGPwIeNRX/xAAYEAACAwAAAAAAAAAAAAAAAAAAESAhUf/aAAgBAQABPyE1gVx//9oADAMBAAIAAwAAABDUD//EABYRAQEBAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxATJ//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABkQAAEFAAAAAAAAAAAAAAAAABEAICFRcf/aAAgBAQABPxBWsYwcb//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Heart wallpaper&quot;
        title=&quot;&quot;
        src=&quot;/static/4e8462db10aca881d2b2f4e0bd1115ec/3cb18/wallpaper-andyet-heart-thumb.jpg&quot;
        srcset=&quot;/static/4e8462db10aca881d2b2f4e0bd1115ec/0a254/wallpaper-andyet-heart-thumb.jpg 151w,
/static/4e8462db10aca881d2b2f4e0bd1115ec/c8fe0/wallpaper-andyet-heart-thumb.jpg 303w,
/static/4e8462db10aca881d2b2f4e0bd1115ec/3cb18/wallpaper-andyet-heart-thumb.jpg 605w,
/static/4e8462db10aca881d2b2f4e0bd1115ec/8e1fc/wallpaper-andyet-heart-thumb.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;a href=&quot;/uploads/wallpaper-andyet-heart.jpg&quot;&gt;Get this wallpaper&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;people-first&quot;&gt;&lt;a href=&quot;#people-first&quot; aria-label=&quot;people first permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;People first&lt;/h2&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 62.251655629139066%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAL/xAAWAQEBAQAAAAAAAAAAAAAAAAAABAX/2gAMAwEAAhADEAAAAbuFGcB//8QAFxABAAMAAAAAAAAAAAAAAAAAAQARIP/aAAgBAQABBQKJWf/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABYQAAMAAAAAAAAAAAAAAAAAAAAgIf/aAAgBAQABPyEkX//aAAwDAQACAAMAAAAQt8//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEAAgMAAAAAAAAAAAAAAAABABEgIVH/2gAIAQEAAT8Qg6lb6Y//2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;People first color wallpaper&quot;
        title=&quot;&quot;
        src=&quot;/static/7028da0a8b31e41e6c32281b4eba81dd/3cb18/wallpaper-andyet-people-first-color-thumb.jpg&quot;
        srcset=&quot;/static/7028da0a8b31e41e6c32281b4eba81dd/0a254/wallpaper-andyet-people-first-color-thumb.jpg 151w,
/static/7028da0a8b31e41e6c32281b4eba81dd/c8fe0/wallpaper-andyet-people-first-color-thumb.jpg 303w,
/static/7028da0a8b31e41e6c32281b4eba81dd/3cb18/wallpaper-andyet-people-first-color-thumb.jpg 605w,
/static/7028da0a8b31e41e6c32281b4eba81dd/8e1fc/wallpaper-andyet-people-first-color-thumb.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;a href=&quot;/uploads/wallpaper-andyet-people-first-color.jpg&quot;&gt;Get this wallpaper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 62.251655629139066%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMBBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe/Og0H/xAAXEAEAAwAAAAAAAAAAAAAAAAACABIg/9oACAEBAAEFAoFbP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABkQAAIDAQAAAAAAAAAAAAAAAAEhABEgUf/aAAgBAQABPyGFsguZ/9oADAMBAAIAAwAAABCwD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABoQAQACAwEAAAAAAAAAAAAAAAEQEQAhMZH/2gAIAQEAAT8Qea7m5gKrS36E1Uf/2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;People first white wallpaper&quot;
        title=&quot;&quot;
        src=&quot;/static/c5870a85bbed20e130d81b6148bc147e/3cb18/wallpaper-andyet-people-first-white-thumb.jpg&quot;
        srcset=&quot;/static/c5870a85bbed20e130d81b6148bc147e/0a254/wallpaper-andyet-people-first-white-thumb.jpg 151w,
/static/c5870a85bbed20e130d81b6148bc147e/c8fe0/wallpaper-andyet-people-first-white-thumb.jpg 303w,
/static/c5870a85bbed20e130d81b6148bc147e/3cb18/wallpaper-andyet-people-first-white-thumb.jpg 605w,
/static/c5870a85bbed20e130d81b6148bc147e/8e1fc/wallpaper-andyet-people-first-white-thumb.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;a href=&quot;/uploads/wallpaper-andyet-people-first-white.jpg&quot;&gt;Get this wallpaper&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;software-is-about-people&quot;&gt;&lt;a href=&quot;#software-is-about-people&quot; aria-label=&quot;software is about people permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Software is about people&lt;/h2&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 62.251655629139066%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIE/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEE/9oADAMBAAIQAxAAAAHNcNMA/8QAGBAAAgMAAAAAAAAAAAAAAAAAAAECESD/2gAIAQEAAQUCJKs//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFBABAAAAAAAAAAAAAAAAAAAAIP/aAAgBAQAGPwJf/8QAFhABAQEAAAAAAAAAAAAAAAAAIQAg/9oACAEBAAE/IYbn/9oADAMBAAIAAwAAABAQL//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABkQAQADAQEAAAAAAAAAAAAAAAEQETEAUf/aAAgBAQABPxDh0N+lSq6rH//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Software is about people color wallpaper&quot;
        title=&quot;&quot;
        src=&quot;/static/adb0240ae4e52a3f978c3cb2e2fbe491/3cb18/wallpaper-andyet-software-color-thumb.jpg&quot;
        srcset=&quot;/static/adb0240ae4e52a3f978c3cb2e2fbe491/0a254/wallpaper-andyet-software-color-thumb.jpg 151w,
/static/adb0240ae4e52a3f978c3cb2e2fbe491/c8fe0/wallpaper-andyet-software-color-thumb.jpg 303w,
/static/adb0240ae4e52a3f978c3cb2e2fbe491/3cb18/wallpaper-andyet-software-color-thumb.jpg 605w,
/static/adb0240ae4e52a3f978c3cb2e2fbe491/8e1fc/wallpaper-andyet-software-color-thumb.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;a href=&quot;/uploads/wallpaper-andyet-software-color.jpg&quot;&gt;Get this wallpaper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 62.251655629139066%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMBBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe/Og0H/xAAXEAEAAwAAAAAAAAAAAAAAAAACABIg/9oACAEBAAEFAoVbP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABcQAAMBAAAAAAAAAAAAAAAAAAARISD/2gAIAQEAAT8hLoln/9oADAMBAAIAAwAAABCwD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABoQAQACAwEAAAAAAAAAAAAAAAEQMQARIWH/2gAIAQEAAT8Qaxux8HcgFAR//9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Software is about people white wallpaper&quot;
        title=&quot;&quot;
        src=&quot;/static/e48180c9e969b82d928281458875182a/3cb18/wallpaper-andyet-software-white-thumb.jpg&quot;
        srcset=&quot;/static/e48180c9e969b82d928281458875182a/0a254/wallpaper-andyet-software-white-thumb.jpg 151w,
/static/e48180c9e969b82d928281458875182a/c8fe0/wallpaper-andyet-software-white-thumb.jpg 303w,
/static/e48180c9e969b82d928281458875182a/3cb18/wallpaper-andyet-software-white-thumb.jpg 605w,
/static/e48180c9e969b82d928281458875182a/8e1fc/wallpaper-andyet-software-white-thumb.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;a href=&quot;/uploads/wallpaper-andyet-software-white.jpg&quot;&gt;Get this wallpaper&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;yeti&quot;&gt;&lt;a href=&quot;#yeti&quot; aria-label=&quot;yeti permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Yeti&lt;/h2&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 62.251655629139066%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAd+bQwD/xAAXEAEAAwAAAAAAAAAAAAAAAAABABEg/9oACAEBAAEFAoNmP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABYQAAMAAAAAAAAAAAAAAAAAAAARIP/aAAgBAQAGPwIc/wD/xAAZEAABBQAAAAAAAAAAAAAAAAAAAREgIXH/2gAIAQEAAT8hK4jbH//aAAwDAQACAAMAAAAQ0A//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAZEAEAAgMAAAAAAAAAAAAAAAABABEgITH/2gAIAQEAAT8QhGgN66x//9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Yeti wallpaper&quot;
        title=&quot;&quot;
        src=&quot;/static/46fc85fb80ec8b6a2493792eb679bf9b/3cb18/wallpaper-andyet-yeti-thumb.jpg&quot;
        srcset=&quot;/static/46fc85fb80ec8b6a2493792eb679bf9b/0a254/wallpaper-andyet-yeti-thumb.jpg 151w,
/static/46fc85fb80ec8b6a2493792eb679bf9b/c8fe0/wallpaper-andyet-yeti-thumb.jpg 303w,
/static/46fc85fb80ec8b6a2493792eb679bf9b/3cb18/wallpaper-andyet-yeti-thumb.jpg 605w,
/static/46fc85fb80ec8b6a2493792eb679bf9b/8e1fc/wallpaper-andyet-yeti-thumb.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;a href=&quot;/uploads/wallpaper-andyet-yeti.jpg&quot;&gt;Get this wallpaper&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;pixels-are-about-people&quot;&gt;&lt;a href=&quot;#pixels-are-about-people&quot; aria-label=&quot;pixels are about people permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Pixels are about people&lt;/h2&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 62.251655629139066%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQCA//EABYBAQEBAAAAAAAAAAAAAAAAAAABA//aAAwDAQACEAMQAAABvT51UuRP/8QAFhABAQEAAAAAAAAAAAAAAAAAEBEA/9oACAEBAAEFAtGn/8QAFhEBAQEAAAAAAAAAAAAAAAAAABMU/9oACAEDAQE/Ac6D/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8Bqv/EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABoQAAIDAQEAAAAAAAAAAAAAAAARASFRgZH/2gAIAQEAAT8hi8OPStGhmRJ//9oADAMBAAIAAwAAABBzH//EABcRAAMBAAAAAAAAAAAAAAAAAAABUXH/2gAIAQMBAT8QTU2f/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAICAwAAAAAAAAAAAAAAAQARIZFBUXH/2gAIAQEAAT8QFLHaW5R6JfRuKyGXEXESp//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Pixels are about people wallpaper&quot;
        title=&quot;&quot;
        src=&quot;/static/8ea0d05d29adc6922cfee8d8671fc396/3cb18/wallpaper-pixels-people-desktop-thumb.jpg&quot;
        srcset=&quot;/static/8ea0d05d29adc6922cfee8d8671fc396/0a254/wallpaper-pixels-people-desktop-thumb.jpg 151w,
/static/8ea0d05d29adc6922cfee8d8671fc396/c8fe0/wallpaper-pixels-people-desktop-thumb.jpg 303w,
/static/8ea0d05d29adc6922cfee8d8671fc396/3cb18/wallpaper-pixels-people-desktop-thumb.jpg 605w,
/static/8ea0d05d29adc6922cfee8d8671fc396/8e1fc/wallpaper-pixels-people-desktop-thumb.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;a href=&quot;/uploads/wallpaper-pixels-people-desktop.jpg&quot;&gt;Get this wallpaper&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing the New SimpleWebRTC]]></title><description><![CDATA[Hey guess what? Today is SimpleWebRTC beta release day! We know how difficult using WebRTC can be, so we decided to make it simple (see the…]]></description><link>https://blog.andyet.com/2018/07/11/introducing-the-new-simplewebrtc/</link><guid isPermaLink="false">https://blog.andyet.com/2018/07/11/introducing-the-new-simplewebrtc/</guid><pubDate>Wed, 11 Jul 2018 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/72623e0af6b89c3331ad69a8d05e0566/8e1fc/simplewebrtc_logo.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 24.50331125827815%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB35Cgf//EABUQAQEAAAAAAAAAAAAAAAAAAABB/9oACAEBAAEFAlf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAWEAADAAAAAAAAAAAAAAAAAAAAEDH/2gAIAQEABj8CKv/EABgQAQADAQAAAAAAAAAAAAAAAAEAEDFB/9oACAEBAAE/IXICdCv/2gAMAwEAAgADAAAAEHPP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGRABAAIDAAAAAAAAAAAAAAAAAQAREFFh/9oACAEBAAE/EBaBTpHlrQmP/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;SimpleWebRTC Logo&quot;
        title=&quot;&quot;
        src=&quot;/static/72623e0af6b89c3331ad69a8d05e0566/3cb18/simplewebrtc_logo.jpg&quot;
        srcset=&quot;/static/72623e0af6b89c3331ad69a8d05e0566/0a254/simplewebrtc_logo.jpg 151w,
/static/72623e0af6b89c3331ad69a8d05e0566/c8fe0/simplewebrtc_logo.jpg 303w,
/static/72623e0af6b89c3331ad69a8d05e0566/3cb18/simplewebrtc_logo.jpg 605w,
/static/72623e0af6b89c3331ad69a8d05e0566/8e1fc/simplewebrtc_logo.jpg 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hey guess what? Today is SimpleWebRTC beta release day! We know how difficult using WebRTC can be, so we decided to make it simple (see the play on words there?).&lt;/p&gt;
&lt;p&gt;SimpleWebRTC allows you to add video, voice, text chat, and screen-sharing to your app with easy to use React components. And as of today, &lt;a href=&quot;https://simplewebrtc.com/&quot;&gt;you can try it out for free&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/webrtc-illustration-f47935c1c206c4e6dadd94cbf848a595.gif&quot; alt=&quot;WebRTC Illustration&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-about-the-old-version&quot;&gt;&lt;a href=&quot;#what-about-the-old-version&quot; aria-label=&quot;what about the old version permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about the old version?&lt;/h2&gt;
&lt;p&gt;This version of SimpleWebRTC is quite different than previous versions. It uses React, for one. There are lots of other differences, which &lt;a href=&quot;https://blog.andyet.com/2018/07/09/react-appropriately&quot;&gt;we wrote about earlier this week&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We hope you &lt;a href=&quot;https://simplewebrtc.com/&quot;&gt;give the new SimpleWebRTC a try&lt;/a&gt;, and &lt;a href=&quot;https://andyet.com/contact&quot;&gt;let us know what you think&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Starters, finishers, and large development teams]]></title><description><![CDATA[When evaluating programmers, it’s very easy to see the value of someone writing a lot of new code. Do not, however, fall into the trap of…]]></description><link>https://blog.andyet.com/2018/07/10/starters-finishers-and-large-teams/</link><guid isPermaLink="false">https://blog.andyet.com/2018/07/10/starters-finishers-and-large-teams/</guid><pubDate>Tue, 10 Jul 2018 15:35:00 GMT</pubDate><content:encoded>&lt;p&gt;When evaluating programmers, it’s very easy to see the value of someone writing a lot of new code. Do not, however, fall into the trap of only valuing developers that write quickly. A healthy project has a mix of developers in terms of values, strengths, and weaknesses.&lt;/p&gt;
&lt;p&gt;One productive way to categorize programmers is starters and finishers.&lt;/p&gt;
&lt;p&gt;A starter creates a vision for new code and writes the initial version, prototype, or skeleton. Starters usually lack motivation for bringing the project to the next level, making it easier for others to work on the code, or generally polishing. That isn’t to say that they can’t do it — it just costs them much more mental energy than a finisher, so they often don’t.&lt;/p&gt;
&lt;p&gt;A finisher, conversely, takes an existing vision, fills in the details, and turns it into something more practical. That might be implementing a spec (and suggesting revisions), rewriting a prototype, filling in a skeleton or tracer, making a project production ready, or making a project easier for new contributors to on-board. Finishers struggle with a blank sheet of paper in the same way that starters struggle to improve the work of others.&lt;/p&gt;
&lt;h2 id=&quot;balancing-starters-and-finishers&quot;&gt;&lt;a href=&quot;#balancing-starters-and-finishers&quot; aria-label=&quot;balancing starters and finishers permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Balancing starters and finishers&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“If a programmer takes one month to finish a task, two programmers can finish that same task in two months.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Anecdotally, this outcome feels true, but it’s the result of an unbalanced team. Teams comprised entirely of starters take more time to bring a project to completion. The problem only gets worse as teams get bigger.&lt;/p&gt;
&lt;p&gt;As consultants, we often meet managers that limit teams to 5 or 6 programmers, because experience tells them that adding more to a team will not result in more productivity. This a direct result of hiring/filtering their developers by a naive set of values. They don’t have enough finishers, and more specifically, they don’t have anyone guarding the cultural value of project sustainability, reducing the overhead to contribute to a project. They’ve filled their team with starters because management (and the team) over-values this type of programmer.&lt;/p&gt;
&lt;h2 id=&quot;large-teams-need-an-additional-developer-type&quot;&gt;&lt;a href=&quot;#large-teams-need-an-additional-developer-type&quot; aria-label=&quot;large teams need an additional developer type permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Large teams need an additional developer-type&lt;/h2&gt;
&lt;p&gt;Within finishers, there are detail-oriented people who excel at making large teams productive by reducing the cognitive overhead of a project. These “sustainability guards” or simply “guards” are bothered by project pitfalls, because they value maintainable and sustainable projects, while most other developers would simply work through and around these problems.&lt;/p&gt;
&lt;p&gt;Nowhere are the problems that prevent large teams from being effective more obvious than when on-boarding a new developer into a project. If a project is hard to get running locally, a guard might simply state, “I can’t run your code.” They could, and they will, but really what they’re saying is that they’re going to have to repeat the work of others in order to get the project going; their value for sustainability is being challenged. Maybe the documentation is lacking, there are environment assumptions, or unmaintained dependencies. Maybe there aren’t proper data fixtures, or there aren’t sufficient tests to show the intent of the code. When a guard says that they “can’t” do something, they’re just being overly nice by claiming responsibility; don’t confuse this for incompetence!&lt;/p&gt;
&lt;p&gt;Due to their values, a guard will want to make on-boarding smoother. They’ll want to expand and fix documentation and tests, as well as root out code that isn’t self-evident. You should let them do this, because it will benefit all of your programmers, including project veterans. Everyone will waste less time and energy loading the mental context of the project and spend less time on project overhead like repeated debugging and in-project research.&lt;/p&gt;
&lt;h2 id=&quot;balancing-your-teams&quot;&gt;&lt;a href=&quot;#balancing-your-teams&quot; aria-label=&quot;balancing your teams permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Balancing your teams&lt;/h2&gt;
&lt;p&gt;In order have productive programming teams of any size, make sure to keep a balance of starters, finishers, and guards. It’s easy to do yourself a disservice by filtering out programmers who aren’t great starters.&lt;/p&gt;
&lt;p&gt;In order to make your programming team efficient as it grows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cultivate a team culture of valuing starters and finishers through hiring and internal discussion. Requiring the same strengths from all of your developers is a recipe for inefficiency.&lt;/li&gt;
&lt;li&gt;Get to know the strengths and weaknesses of all of your programmers so that you can balance them with each other to efficiently produce quality code.&lt;/li&gt;
&lt;li&gt;Make sure at least one of your programmers is a guard that values maintainability and sustainability to keep the project efficient.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It takes all types to make a programming team efficient; merely filling your team with high quality programmers is not enough.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[A whole new SimpleWebRTC is coming. React, appropriately.]]></title><description><![CDATA[Very soon we’ll be shipping a brand new version of SimpleWebRTC, and everything about it is different.What’s different?The biggest feature…]]></description><link>https://blog.andyet.com/2018/07/09/react-appropriately/</link><guid isPermaLink="false">https://blog.andyet.com/2018/07/09/react-appropriately/</guid><pubDate>Mon, 09 Jul 2018 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Very soon we’ll be shipping a brand new version of SimpleWebRTC, and everything about it is different.&lt;/p&gt;
&lt;h2 id=&quot;whats-different&quot;&gt;&lt;a href=&quot;#whats-different&quot; aria-label=&quot;whats different permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’s different?&lt;/h2&gt;
&lt;p&gt;The biggest feature of the soon-to-be-released version of SimpleWebRTC is that it will just be a bunch of flexible React components.&lt;/p&gt;
&lt;p&gt;These components will make it so that anyone with a basic understanding of React can build advanced WebRTC applications. No need to understand anything about how connections are set up, no need to set up signaling or STUN/TURN servers, and it gets even better than that.&lt;/p&gt;
&lt;p&gt;One of the hardest things about building a WebRTC app is that you’re building a realtime app. As we’ve learned over nearly a decade of building realtime web applications, building high quality performant UX in a realtime app is significantly harder than throwing together a cute demo.&lt;/p&gt;
&lt;p&gt;The new version of SimpleWebRTC will provide a bunch of pre-built UX solutions that can be styled however you’d like.&lt;/p&gt;
&lt;h2 id=&quot;react-native-for-mobile-too&quot;&gt;&lt;a href=&quot;#react-native-for-mobile-too&quot; aria-label=&quot;react native for mobile too permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;React Native for mobile, too&lt;/h2&gt;
&lt;p&gt;In addition to React components for web applications, we’ve also developed a React Native toolkit for adding these features to iOS and Android native mobile applications.&lt;/p&gt;
&lt;p&gt;It’s possible on Android to build progressive web apps with WebRTC functionality using our SimpleWebRTC React components, but as an Android developer you’ll be able to choose which toolkit is right for you based on your application’s needs.&lt;/p&gt;
&lt;h2 id=&quot;oh-and-one-more-thing&quot;&gt;&lt;a href=&quot;#oh-and-one-more-thing&quot; aria-label=&quot;oh and one more thing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Oh, and one more thing:&lt;/h2&gt;
&lt;p&gt;This summer, we&apos;ll share regular updates on our progress while we rewrite Talky using the new SimpleWebRTC, and we’ll be sharing the entire Talky client source code afterwards.&lt;/p&gt;
&lt;p&gt;Psst… Here’s a sneak preview of the new Talky UI:&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/212452caf167d633131e2c07c19ea3cf/1acf3/talky_screenshot.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 66.88741721854305%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAADtUlEQVQ4yw2Te0zUBQDHf/3bsrbYWM5K0WVZGYVNmDyVh7LFIXIC8jq4A47Au+N43B0cHCHHS4838hwULHmYHlBIgBuJ8g7lQBQSnPHUmYOC0q2tfbp/vt8/v699Bb2PiMRzfkhEbrgffp8j+21x/fRdQj2+pNhPQlRkCO4n3ImMjkCdnkFObj6hkdGESaSEWFkSISUwQkK9RwS1TsEIJo2UnPjTSDwOcOqjt3Dbvwunfa8T6LyPlCBXxCcccHbxQp6QRFZePgp1Ctm5eeSVlGPMyKBSoUSjUpOWfQG1Vo9gme6n92oTubE+TFam8F2CP5n+R1H62ZMWfpyGPAU3e67T8o2OBqOB4uo6LhQUkmrIITUqlChHB8LEYpL0BhRpOoS5Z0O8fPU3o+YGZhov0aWV0xgrpjhOTLs5mdmV73m+s0mXMYm6FBk6YyGm0lJar5nJV8Tg+96bqJVKDPkXkSWqEC6bUrnRUcmN2ouUyQLRidyRun5OcsBxmjsz+GWhiPHfSjDlKtDKo+ho7WB9bZ2dv7ZZnZ9joKWeJ/MPWFtd5apVRNCEelGgFDPeXEZbqpwSiTXyGW/0wSdp7NRyb6WOkUdFJKoCkJ8NoP96G5aJEbY2t9j+5yX//gevrLC89Jj7Y3cQksJF5GtjmeprYiBHxTW1lLJQX0ojxUwPj7M0b2HO0kVEiCOp1p7PB7kgD/JkYmiQ9aUFhnq7mbjZgylLg7+nC0J1kZ7WlirGW/uYLM/k5ywFZed8STvmTY2/nt7sbLoMp5AdegO33TZ4H7Ql2tcZk0FLz7d1qCUBaGQiIrydKDZaV+5uv8JEySz9ZzqZrc1nvCKbqpjTxNq5UeAUxpgphS5NPLK9e3hbeI3dNrb4HrWnLlnO7eoSKjJVhIm+okYXhU4RhzBqmKXT/UfKDxbRHKmlI1NKTWwQ9f5fU+ulZMqkoUsn48gHBzjm6IbI0wtPn2By5efpzNYQG5dJiH88l+QJfLLLBqHP9xaVh8swfVhEtVMxLclKamLktIcbMCcquF9lZLIknWJ1uNVBPPrCelo6R3n8YJGl2YfM3HvE3MwScxOziD0cEao+qyTdToPqnUSK9hRQ9oWB9EPRVNjnMGhMx1KTx93LRgI9HPjYbi8nQ1TWl9SyvPyEleXfebH5gj+eP+XP7R1S0pMQypvaqWi4wmDrKFPmOUba7jLcOsX4D9MsTFrYeGjh9vAYuS09/HTrV7oHRzH3DrC0uMjayjJPt3ZY23jG6sYGvXem+R+yL5mdzwCftwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Talky UI Screenshot&quot;
        title=&quot;&quot;
        src=&quot;/static/212452caf167d633131e2c07c19ea3cf/90cbd/talky_screenshot.png&quot;
        srcset=&quot;/static/212452caf167d633131e2c07c19ea3cf/29fe9/talky_screenshot.png 151w,
/static/212452caf167d633131e2c07c19ea3cf/6728c/talky_screenshot.png 303w,
/static/212452caf167d633131e2c07c19ea3cf/90cbd/talky_screenshot.png 605w,
/static/212452caf167d633131e2c07c19ea3cf/a2b88/talky_screenshot.png 908w,
/static/212452caf167d633131e2c07c19ea3cf/a3767/talky_screenshot.png 1210w,
/static/212452caf167d633131e2c07c19ea3cf/1acf3/talky_screenshot.png 1596w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-about-hosting&quot;&gt;&lt;a href=&quot;#what-about-hosting&quot; aria-label=&quot;what about hosting permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about hosting?&lt;/h2&gt;
&lt;p&gt;The new version of SimpleWebRTC will be fully hosted by &amp;#x26;yet on infrastructure similar to what we use for Talky.&lt;/p&gt;
&lt;p&gt;We’ll also be able to provide sandboxed private servers for those who require this for HIPAA compliance.&lt;/p&gt;
&lt;h2 id=&quot;pricing&quot;&gt;&lt;a href=&quot;#pricing&quot; aria-label=&quot;pricing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Pricing&lt;/h2&gt;
&lt;p&gt;Yep, you read that. Pricing.&lt;/p&gt;
&lt;p&gt;This time around we&apos;ve decided to charge money for our product. This will allow us to keep working on it and keep it awesome for years to come.&lt;/p&gt;
&lt;p&gt;One of the critical differences with this new version of SimpleWebRTC is that it will have a freemium model instead of being purely open source.&lt;/p&gt;
&lt;p&gt;Our goal is to empower a whole new generation of developers to build innovative WebRTC applications while we work behind the scenes to keep up with browser idiosyncracies and solving the hard, boring parts.&lt;/p&gt;
&lt;h2 id=&quot;why-this-new-direction&quot;&gt;&lt;a href=&quot;#why-this-new-direction&quot; aria-label=&quot;why this new direction permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why this new direction?&lt;/h2&gt;
&lt;p&gt;There’s a lot that’s happened, and we&apos;ve learned a lot since &amp;#x26;yet released &lt;a href=&quot;https://blog.andyet.com/2013/02/22/introducing-simplewebrtcjs-and-conversatio/&quot;&gt;the first version of SimpleWebRTC&lt;/a&gt; more than five years ago.&lt;/p&gt;
&lt;p&gt;The first version of Talky was built on top of SimpleWebRTC. In fact, it was built as a demo of SimpleWebRTC. Since that time we’ve taken huge steps with our WebRTC tools that have left SimpleWebRTC in the dust.&lt;/p&gt;
&lt;p&gt;One thing that we learned is that while there are scores of people who have used SimpleWebRTC, there are very few people knowledgeable enough to contribute to it as a collaborative open source effort, and maintaining it is an extremely costly endeavor. We have been lucky to have a few contributors and maintainers outside of &amp;#x26;yet, but for the most part, it’s been an unsustainable public service.&lt;/p&gt;
&lt;p&gt;When &amp;#x26;yet stopped maintaining SimpleWebRTC, we continued to devote our energy toward developing, maintaining and improving tools that helped our organization rapidly build custom WebRTC applications for our clients.&lt;/p&gt;
&lt;p&gt;And after several years worth of development, this is what we’re going to be sharing in a few weeks.&lt;/p&gt;
&lt;h2 id=&quot;what-will-happen-to-the-original-simplewebrtc&quot;&gt;&lt;a href=&quot;#what-will-happen-to-the-original-simplewebrtc&quot; aria-label=&quot;what will happen to the original simplewebrtc permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What will happen to the original SimpleWebRTC?&lt;/h2&gt;
&lt;p&gt;We like to be good open source stewards and so our intent is to deprecate the original outdated 2013 edition of SimpleWebRTC, but we will leave the library and prior documentation available, with deprecation notices in place.&lt;/p&gt;
&lt;p&gt;Before moving forward with this direction, we sought and gained approval from major SimpleWebRTC contributors.&lt;/p&gt;
&lt;p&gt;We believe that this is the best direction for the future of SimpleWebRTC and will help bring these tools to a whole new audience, helping developers build applications with WebRTC using very familiar tools.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Celebrate Pride with your friends at &yet! 🏳️‍🌈]]></title><description><![CDATA[Earlier this year, we teamed up with our friends at npm to design some shirts for Pride. When they asked us about working with them on the…]]></description><link>https://blog.andyet.com/2018/06/18/celebrate-pride-with-andyet/</link><guid isPermaLink="false">https://blog.andyet.com/2018/06/18/celebrate-pride-with-andyet/</guid><pubDate>Mon, 18 Jun 2018 09:51:00 GMT</pubDate><content:encoded>&lt;p&gt;Earlier this year, we teamed up with our friends at &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt; to design some &lt;a href=&quot;https://blog.npmjs.org/post/174469070810/npm-pride-2018-shirts&quot;&gt;shirts for Pride&lt;/a&gt;. When they asked us about working with them on the project, we said, “Yes, please!” and then had an idea to do something of our own.&lt;/p&gt;
&lt;p&gt;We believe being &lt;a href=&quot;https://blog.andyet.com/2017/02/02/people-first&quot;&gt;People First&lt;/a&gt; means standing with the LGBTQI+ community during Pride month (and every other month). In 2015 one of our designers, &lt;a href=&quot;http://andyet.com/team/amy&quot;&gt;Amy Lynn Taylor&lt;/a&gt;, made a version of our logo with the Pride colors to show our support for Marriage Equality. We really like the design and, in true &amp;#x26;yet fashion, thought it was time to put it on a shirt!&lt;/p&gt;
&lt;p&gt;These Ampersand Pride shirts are now available with 100% of the proceeds going to &lt;a href=&quot;https://www.thetrevorproject.org&quot;&gt;The Trevor Project&lt;/a&gt;, an amazing organization that provides crisis intervention and suicide prevention for LGBTQI+ youth.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3d879c1dc49e8e7c4349c7da75ba089d/4b190/pride-shirts-feature1.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 52.980132450331126%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMCBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABU/VlSiyR/8QAGhABAAIDAQAAAAAAAAAAAAAAAgEDAAQTEv/aAAgBAQABBQKU+25LFmt6mjhXKdQeEwT/AP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABsQAAIDAQEBAAAAAAAAAAAAAAERAAISIhMx/9oACAEBAAY/As+ltaTg7PyVNrNzWA53UGIBCf/EABsQAQADAQADAAAAAAAAAAAAAAEAESExQWHB/9oACAEBAAE/ITLG7PkMc3gyNAPW+I2rXd+42Kpy4GrHCf/aAAwDAQACAAMAAAAQUA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCn/8QAHBABAQADAAMBAAAAAAAAAAAAAREAITFBUXGB/9oACAEBAAE/EF+3RJLL4fnMGTXCSJp577hBYhBR6vn7jRpXne1uAkGIbDCHDgcDP//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Two design options!&quot;
        title=&quot;&quot;
        src=&quot;/static/3d879c1dc49e8e7c4349c7da75ba089d/3cb18/pride-shirts-feature1.jpg&quot;
        srcset=&quot;/static/3d879c1dc49e8e7c4349c7da75ba089d/0a254/pride-shirts-feature1.jpg 151w,
/static/3d879c1dc49e8e7c4349c7da75ba089d/c8fe0/pride-shirts-feature1.jpg 303w,
/static/3d879c1dc49e8e7c4349c7da75ba089d/3cb18/pride-shirts-feature1.jpg 605w,
/static/3d879c1dc49e8e7c4349c7da75ba089d/4b190/pride-shirts-feature1.jpg 800w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;h5 id=&quot;bonfirecombig-ampersand-pride-and-bonfirecomlil-ampersand-pride&quot;&gt;&lt;a href=&quot;#bonfirecombig-ampersand-pride-and-bonfirecomlil-ampersand-pride&quot; aria-label=&quot;bonfirecombig ampersand pride and bonfirecomlil ampersand pride permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;http://bonfire.com/big-ampersand-pride&quot;&gt;bonfire.com/big-ampersand-pride&lt;/a&gt; and &lt;a href=&quot;http://bonfire.com/lil-ampersand-pride&quot;&gt;bonfire.com/lil-ampersand-pride&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;You might be thinking - &lt;em&gt;“Oh wow, I like these, but I wish there were more colors to choose from.”&lt;/em&gt; Great news! More colors:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/pride-shirts-feature2-1920a68663ad9e4c792c9d65dd21921b.gif&quot; alt=&quot;All the colors!&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now you’re probably thinking… &lt;em&gt;“Hmm…that’s great, but I have too many t-shirts like that.”&lt;/em&gt; Well, we’ve got you covered there with fitted tees, youth tees, pullover hoodies, and crewneck sweatshirts!&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f38379b7a9f07e48c329fe1d2e8fef99/4b190/pride-shirts-feature3.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 37.748344370860934%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIE/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB0yFg/8QAGRAAAgMBAAAAAAAAAAAAAAAAAQQCAxMS/9oACAEBAAEFAuGMzUxtXFkR/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHRAAAAUFAAAAAAAAAAAAAAAAAAEREjECMkFSkf/aAAgBAQAGPwKanLsDN2JUXdMf/8QAGxABAAICAwAAAAAAAAAAAAAAAQARIUExUXH/2gAIAQEAAT8hNW004qKOwsHlgqZZt2T/2gAMAwEAAgADAAAAEHgv/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQIBAT8Qp//EABwQAQEAAgIDAAAAAAAAAAAAAAERADEhcUFhgf/aAAgBAQABPxCAFTUnuvfjFNuKKnQb5s3cmZLUFn2Of//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Several styles to choose from!&quot;
        title=&quot;&quot;
        src=&quot;/static/f38379b7a9f07e48c329fe1d2e8fef99/3cb18/pride-shirts-feature3.jpg&quot;
        srcset=&quot;/static/f38379b7a9f07e48c329fe1d2e8fef99/0a254/pride-shirts-feature3.jpg 151w,
/static/f38379b7a9f07e48c329fe1d2e8fef99/c8fe0/pride-shirts-feature3.jpg 303w,
/static/f38379b7a9f07e48c329fe1d2e8fef99/3cb18/pride-shirts-feature3.jpg 605w,
/static/f38379b7a9f07e48c329fe1d2e8fef99/4b190/pride-shirts-feature3.jpg 800w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;All colors and options are available in the Big Ampersand or Lil’ Ampersand design from size XS to 3X. Orders will be open until June 28th. Shirts will arrive around the second week of July.&lt;/p&gt;
&lt;h3 id=&quot;go-to-bonfirecombig-ampersand-pride-and-bonfirecomlil-ampersand-pride-get-yours&quot;&gt;&lt;a href=&quot;#go-to-bonfirecombig-ampersand-pride-and-bonfirecomlil-ampersand-pride-get-yours&quot; aria-label=&quot;go to bonfirecombig ampersand pride and bonfirecomlil ampersand pride get yours permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Go to &lt;a href=&quot;http://bonfire.com/big-ampersand-pride&quot;&gt;bonfire.com/big-ampersand-pride&lt;/a&gt; and &lt;a href=&quot;http://bonfire.com/lil-ampersand-pride&quot;&gt;bonfire.com/lil-ampersand-pride&lt;/a&gt; get yours!&lt;/h3&gt;</content:encoded></item><item><title><![CDATA[Simplifying the Talky ecosystem with React Native]]></title><description><![CDATA[To the thousands of people who made Talky calls on February 14, 2017, Talky didn’t seem much different. There were some icon and button…]]></description><link>https://blog.andyet.com/2018/06/14/simplifying-the-talky-ecosystem-with-react-native/</link><guid isPermaLink="false">https://blog.andyet.com/2018/06/14/simplifying-the-talky-ecosystem-with-react-native/</guid><pubDate>Thu, 14 Jun 2018 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To the thousands of people who made Talky calls on February 14, 2017, Talky didn’t seem much different. There were some icon and button color changes, but nothing to write home about. However, it was a very big day in our world.&lt;/p&gt;
&lt;p&gt;For the past couple of years, we&apos;ve been transitioning Talky from AmpersandJS to React. The reason for the transition is an article on its own, but to put it simply, I only need one word. Components, heard of &apos;em?&lt;/p&gt;
&lt;p&gt;During the rewrite, we moved the core functionality of Talky into its own library of super slick React components which... &lt;strong&gt;[SPOILER ALERT]&lt;/strong&gt; we&apos;ll very soon be making available to anyone who wants to build an app using them. This very simple webrtc react library enables us to build robust video chat features in very little time at all, and we&apos;re excited to say we&apos;ll be sharing it with the world in the coming months. 🎉&lt;/p&gt;
&lt;p&gt;While Talky on the web was receiving consistent upgrades, our Talky iOS application hadn&apos;t been updated in quite some time, and it really needed an overhaul to take advantage of some backend upgrades. When trying to figure out what to do about our iOS application we had two options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Swift&lt;/li&gt;
&lt;li&gt;React Native&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&apos;ll notice I didn&apos;t include Objective C. I don’t know if you&apos;ve ever seen that language, but I&apos;m pretty sure I&apos;d have a better chance understanding ancient hieroglyphs.&lt;/p&gt;
&lt;h2 id=&quot;choosing-between-react-native-and-swift&quot;&gt;&lt;a href=&quot;#choosing-between-react-native-and-swift&quot; aria-label=&quot;choosing between react native and swift permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Choosing between React Native and Swift&lt;/h2&gt;
&lt;h3 id=&quot;react-native&quot;&gt;&lt;a href=&quot;#react-native&quot; aria-label=&quot;react native permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;React Native&lt;/h3&gt;
&lt;p&gt;React Native is an interesting beast with a very cool approach to writing mobile applications—it lets you write the app in Javascript (WHOA!). A few years ago when I was learning to code, I remember dabbling with it and being impressed, but it seemed very young and not production ready. It&apos;s really amazing how far it&apos;s come in just a few short years.&lt;/p&gt;
&lt;p&gt;React Native works by translating JSX into native iOS and Android &lt;code class=&quot;language-text&quot;&gt;UIView&lt;/code&gt;&apos;s and &lt;code class=&quot;language-text&quot;&gt;Views&lt;/code&gt;. The main and Javascript thread communicate through a &quot;bridge&quot; which allows your Javascript code to handle application logic. There&apos;s obviously a lot more to it, but I don&apos;t quite feel qualified enough to try and explain it (it&apos;s literally magic).&lt;/p&gt;
&lt;h3 id=&quot;swift-and-java-android&quot;&gt;&lt;a href=&quot;#swift-and-java-android&quot; aria-label=&quot;swift and java android permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Swift and Java (Android)&lt;/h3&gt;
&lt;p&gt;Writing native code for the platform would require use to rewrite all of the webrtc react library logic &lt;em&gt;twice&lt;/em&gt;. On top of that, we&apos;re primarily a Javascript shop, so we&apos;d be learning two new languages along with writing the application from scratch. While this does sound like fun, we just didn&apos;t have that kind of time.&lt;/p&gt;
&lt;p&gt;We decided to go with React Native.&lt;/p&gt;
&lt;h2 id=&quot;alljavascriptlibraries--reactnativecompatible&quot;&gt;&lt;a href=&quot;#alljavascriptlibraries--reactnativecompatible&quot; aria-label=&quot;alljavascriptlibraries  reactnativecompatible permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;allJavascriptLibraries !== reactNativeCompatible&lt;/h2&gt;
&lt;p&gt;There are a number of core Node modules that don&apos;t work with React Native out of the box such as &lt;code class=&quot;language-text&quot;&gt;crypto&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;buffer&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;events&lt;/code&gt;. As you can imagine, a number of libraries in our dependecy tree for our webrtc react library depend on those. Luckily RN-Nodeify creates a &lt;code class=&quot;language-text&quot;&gt;shim.js&lt;/code&gt; file that installs and shims the necessary modules for you. More magic!&lt;/p&gt;
&lt;p&gt;In our webrtc react library, we also depend on a number of &lt;code class=&quot;language-text&quot;&gt;window&lt;/code&gt; properties that are only found in the browser. React Native doesn&apos;t use the browser so we need to create a &lt;code class=&quot;language-text&quot;&gt;shim.webrtc.js&lt;/code&gt; file for this as well.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const WebRTC = require(&amp;#39;react-native-webrtc&amp;#39;);
const {
  RTCPeerConnection,
  RTCIceCandidate,
  RTCSessionDescription,
  getUserMedia,
} = WebRTC;
global.window = global.window || {};
global.window.WebSocket = WebSocket;
global.window.RTCPeerConnection = RTCPeerConnection;
global.RTCPeerConnection = RTCPeerConnection;
global.RTCSessionDescription = RTCSessionDescription;
global.RTCIceCandidate = RTCIceCandidate;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Both of these files are imported at the very top of the very top of our component tree files. Most commonly &lt;code class=&quot;language-text&quot;&gt;App.js&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WebRTC library orientation&lt;/strong&gt;
An interesting problem we encountered was actually in the WebRTC iOS SDK that was included with &lt;a href=&quot;https://github.com/oney/react-native-webrtc&quot;&gt;React-Native-Webrtc&lt;/a&gt;. The underlying video stream’s orientation wouldn’t change after pausing and resuming the local video feed and then rotating the phone. This ended up making the stream look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://d2mxuefqeaa7sj.cloudfront.net/s_ABFAB57A27AB868559E718E6C6B5A37A89531896669596A741FF18D89830CA21_1518193775556_image.png&quot; alt=&quot;Everything is under control&quot;&gt;&lt;/p&gt;
&lt;p&gt;We spent days searching for what in the world was going on and finally realized that we were probably going to need to lock the orientation of the stream. This required us to build WebRTC from source and modify some of the code in the iOS SDK.&lt;/p&gt;
&lt;p&gt;Now as a noob web developer this was a daunting task. I had to download all these scary Google build tools and then do this thing called &quot;compile&quot; which apparently takes an astronomical amount of time the first time you do it. My fans sounded like my MacBook was about to take flight so I went upstairs to make some coffee while my new in-home wind turbine did its thing.&lt;/p&gt;
&lt;p&gt;After linking, building, and compiling the library for what felt like the hundredth time, the project finally built with no errors and made a peer to peer connection! Surprisingly, something unintentional happened when this finally built...the bug was fixed! Apparently between v58 and v62 of WebRTC this orientation issue was fixed. Hooray!&lt;/p&gt;
&lt;p&gt;A couple of weeks passed and we noticed what was dubbed the &quot;Yaw Bug&quot;. Basically, when you changed the &quot;yaw&quot; (screen face up vs. screen face down) of your device while in landscape, the camera orientation changed to portrait.&lt;/p&gt;
&lt;p&gt;Luckily we knew exactly where the video orientation was being done and started &lt;a href=&quot;https://chromium.googlesource.com/external/webrtc/+/branch-heads/62/webrtc/sdk/objc/Framework/Classes/PeerConnection/RTCCameraVideoCapturer.m#200&quot;&gt;looking at the code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This line here told the whole story. You&apos;ll notice it&apos;s inside the &lt;code class=&quot;language-text&quot;&gt;captureOutput&lt;/code&gt; function that fires on device orientation change. It checks to see what orientation the device is and then changes the video&apos;s orientation based on that. Inside the &lt;code class=&quot;language-text&quot;&gt;switch&lt;/code&gt; statement &lt;a href=&quot;https://chromium.googlesource.com/external/webrtc/+/branch-heads/62/webrtc/sdk/objc/Framework/Classes/PeerConnection/RTCCameraVideoCapturer.m#226&quot;&gt;we can also see&lt;/a&gt; that on &lt;code class=&quot;language-text&quot;&gt;UIDeviceOrientationFaceUp&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;UIDeviceOrientationFaceDown&lt;/code&gt; we just ignore and return the default &lt;code class=&quot;language-text&quot;&gt;_rotation&lt;/code&gt;...which is 90 degrees.&lt;/p&gt;
&lt;p&gt;This works if we&apos;re laying in our bed with the phone in portrait mode, but in landscape it means you end up looking at your face sideways. Which is kinda cool, but also kinda annoying. Thinking about trying to pass this off as a feature and not a bug, we thought better of it and decided to fix it.&lt;/p&gt;
&lt;p&gt;The solution was pretty straight forward. We just needed to move that variable declaration into the upper scope so it didn&apos;t reset the &lt;code class=&quot;language-text&quot;&gt;_rotation&lt;/code&gt; variable on every layout change!&lt;/p&gt;
&lt;h2 id=&quot;what-about-android&quot;&gt;&lt;a href=&quot;#what-about-android&quot; aria-label=&quot;what about android permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about Android?&lt;/h2&gt;
&lt;p&gt;We’re super close to releasing the Android version of the app. Android posed some interesting challenges with how VoIP notifications are handled, but we made it past those. There are a number of methods in React Native that are either iOS-only or Android-only. Importing the &lt;code class=&quot;language-text&quot;&gt;Platform&lt;/code&gt; module and checking &lt;code class=&quot;language-text&quot;&gt;Platform.OS&lt;/code&gt; makes getting around those issues super easy!&lt;/p&gt;
&lt;p&gt;We&apos;re incredibly excited about eventually having an Android app in the pipeline. Plus having both Platforms in one codebase and written in Javascript allows any of our developers to pick up and iterate on it without needing to learn a new language with new syntax.&lt;/p&gt;
&lt;p&gt;Working with React Native has been a great experience overall. The tooling is wonderful, and the development flow makes writing mobile applications for a web developer a cinch! Sometimes a small change in user-land can represent a huge change in dev-land. A huge thank you to Facebook and all the open source contributors who helped make this possible. If you want to learn more about &amp;#x26;yet’s unique approach to web and mobile development check out our &lt;a href=&quot;https://andyet.com/software&quot;&gt;website&lt;/a&gt; or &lt;a href=&quot;https://andyet.com/contact&quot;&gt;reach out to us&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Giving Talky a Case of the Zoomies]]></title><description><![CDATA[On the last page of Matt Nelson's seminal work "#WeRateDogs: The Most Hilarious and Adorable Pups You've Ever Seen", you'll find a…]]></description><link>https://blog.andyet.com/2018/06/06/giving-talky-a-case-of-the-zoomies/</link><guid isPermaLink="false">https://blog.andyet.com/2018/06/06/giving-talky-a-case-of-the-zoomies/</guid><pubDate>Wed, 06 Jun 2018 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On the last page of Matt Nelson&apos;s seminal work &quot;#WeRateDogs: The Most Hilarious and Adorable Pups You&apos;ve Ever Seen&quot;, you&apos;ll find a definition for the word &quot;zoom&quot;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;zoom
/zoom/
&lt;em&gt;noun&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A very speedy move done by a dog. Incredibly hard to document, but universally recognized as a thing that happens. Appears to break laws of physics, but only because when your dog does something average, you think it is the greatest thing ever.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most dog owners (and even owners of some ambitious cats) are familiar with these &quot;zooms&quot;, also referred to as &quot;zoomies&quot;. For those of you who aren&apos;t, let me point you in the direction of &lt;a href=&quot;https://twitter.com/dstaley/status/893270838002294784&quot;&gt;this instructional video from my dog, Jpeg&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A few months after I joined &amp;#x26;yet, I wanted to give our flagship product Talky a case of the zoomies. Here&apos;s how I did it.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c405c942d69f9cd4efd448e454054152/1cfc2/jpeg-talky-kite.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 47.682119205298015%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsSAAALEgHS3X78AAABeElEQVQoz41Ru07cQBT1B1HlF/IzVGnyC5FooIxIGVIFKgQookVRpKQBEggseJcxyxqvPfZ47XnPnUdmxUtaIsSRRhod3XMf5yQhBB/mEMafXNTbB5Neujl5x76IJD7nfSw/Rmz4cefryt5pLu/IV4i9Bee0C7u/yv0vP9Oj8bDgXBguAVMoWl3NZE1NJxy4xXaJ7LFmjAr745SMWqA2lDM9LvlvxA5H9GKqURfGBMa1KGbQUAD71CIBbfuipBj3vWHKEWYIg0YEPE3TPL88+j7bet+iP1GctxphlRNtH1aY36yN8aAUhJoCoabkoUID+/mtXVsSq0vNhzfDUZY19hrLq0pNiKbKPokfwZQtO130rr69Sfc30M46+rRcb75DV4OTrD2biPM8zjdcuwXx/SYafLTnhpjzJnw7g0HpOmkJVaiS6VT8nfCGwWMQyfMAoiUth1uispJHh7j2VLqqMxlWuAe/kPN/EV2JI6I18aPAd8L2wi7U/AM5PjVeXc+qBQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;A corgi running with a kite with the Talky logo&quot;
        title=&quot;&quot;
        src=&quot;/static/c405c942d69f9cd4efd448e454054152/90cbd/jpeg-talky-kite.png&quot;
        srcset=&quot;/static/c405c942d69f9cd4efd448e454054152/29fe9/jpeg-talky-kite.png 151w,
/static/c405c942d69f9cd4efd448e454054152/6728c/jpeg-talky-kite.png 303w,
/static/c405c942d69f9cd4efd448e454054152/90cbd/jpeg-talky-kite.png 605w,
/static/c405c942d69f9cd4efd448e454054152/1cfc2/jpeg-talky-kite.png 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-fastest-javascript-is-javascript-you-never-run&quot;&gt;&lt;a href=&quot;#the-fastest-javascript-is-javascript-you-never-run&quot; aria-label=&quot;the fastest javascript is javascript you never run permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Fastest JavaScript is JavaScript You Never Run&lt;/h2&gt;
&lt;p&gt;Like almost every website built since 2016, Talky uses React, specifically a slightly modified version of Create React App. Because &amp;#x26;yet is a forward-thinking organization, Talky is also #serverless, so everything renders in the browser. However, our efforts to ensure that every browser ships with an embedded version of Talky have been largely unsuccessful, so it takes several seconds for all of Talky&apos;s bespoke code to be downloaded over The Internet. This means that for a few terrifying moments, browsers display a blank page, giving our users a chance to consider their life choices that have brought them to this harrowing moment.&lt;/p&gt;
&lt;p&gt;As it turns out, there&apos;s a way to reduce the length of time this blank page displays, and that&apos;s by eliminating as much JavaScript as possible. Before embarking on this JavaScript extermination-a-thon, I ran a very scientific benchmark to give myself an idea of the kind of performance increase I could expect.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Ops/sec&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;console.log(&amp;quot;This runs some code.&amp;quot;);&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;68,499 (±3.00%), 100% slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No Code&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;// This doesn&amp;#39;t run any code!&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;746,370,478 (±1.32%), fastest&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As you can see from this exhaustive experimentation, the fastest JavaScript code is code you never run. With these results in hand, I embarked on a journey to ship as little JavaScript as possible.&lt;/p&gt;
&lt;h2 id=&quot;shaving-megabytes-is-easier-than-shaving-yaks&quot;&gt;&lt;a href=&quot;#shaving-megabytes-is-easier-than-shaving-yaks&quot; aria-label=&quot;shaving megabytes is easier than shaving yaks permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Shaving Megabytes is Easier Than Shaving Yaks&lt;/h2&gt;
&lt;p&gt;The first thing I wanted to do was identify easy opportunities to drop or replace third-party libraries that contributed significantly to our main bundle size (which was about 2 MB when I began). Since we&apos;re using a custom version of Create React App, it was easy to add in &lt;a href=&quot;https://www.npmjs.com/package/webpack-bundle-analyzer&quot;&gt;Webpack&apos;s Bundle Analyzer&lt;/a&gt;. Our first analysis wasn&apos;t very promising, reporting that the three largest libraries were &lt;code class=&quot;language-text&quot;&gt;talky-core&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;react-dom&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;react-emojione&lt;/code&gt;, all three of which are absolutely essential to optimal Talky performance. After sharing my findings with Talky&apos;s Number One Fan Lance, he gave me what would end up being the best bit of performance advice:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Honestly, making the home page &lt;em&gt;just&lt;/em&gt; a static file would be more useful.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Despite the complex nature of Talky, the homepage is actually the same across refreshes, making it a perfect candidate for staticification. There was only one issue though: how would we build the homepage in such a way that it knew about the main Talky assets so that we could prefetch them?&lt;/p&gt;
&lt;p&gt;Yet again, the fact that we&apos;re using a custom build of Create React App made this easy. By using Webpack&apos;s &lt;code class=&quot;language-text&quot;&gt;HtmlWebpackPlugin&lt;/code&gt;, we are able to output multiple HTML files, one of which contains our static homepage, and the other that contains the original output of Create React App. For maximum performance we inline all the styles and JavaScript necessary for the homepage. Since we know the output of Create React App, we&apos;re able to also utilize the &lt;code class=&quot;language-text&quot;&gt;prefetch&lt;/code&gt; directive to begin downloading the main bundle necessary for Talky, meaning that by the time a user clicks on &quot;Start a chat&quot;, their browser already has all the Talky code downloaded!&lt;/p&gt;
&lt;h2 id=&quot;gotta-go-fast&quot;&gt;&lt;a href=&quot;#gotta-go-fast&quot; aria-label=&quot;gotta go fast permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Gotta Go Fast&lt;/h2&gt;
&lt;p&gt;When we shipped the new static version of Talky&apos;s homepage, we saw a ten-fold decrease in page load time. Our first meaningful paint is now just barely over one second, down from almost 12 seconds prior to the changes. The changes were immediately apparent to other members of our team, but I still wasn&apos;t satisfied. While we were able to bring our main bundle size down to 265 KB gzipped (down from 358 KB), I knew that we could shave off another 30 KB or so by switching from React to &lt;a href=&quot;https://preactjs.com/&quot;&gt;Preact&lt;/a&gt;, a library that offers a similar API to React at under 3 KB (!!!). Switching was as easy as defining an alias from &lt;code class=&quot;language-text&quot;&gt;React&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;Preact&lt;/code&gt; in Webpack. While most things worked (including joining a room and seeing video feeds), others broke in unexpected ways (particularly the chat input). Since we use Redux for state management, it wasn&apos;t exactly straightfoward to debug, so we&apos;ve tabled the switch from React to Preact for another day.&lt;/p&gt;
&lt;p&gt;While most of our speed optimizations focused on the homepage, we&apos;re still thinking about how we can improve the speed (and perceived speed) of the main Talky application. We have some really clever ideas, and can&apos;t wait for you to see (and feel!) the results.&lt;/p&gt;
&lt;p&gt;Stay zoomy my friends!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What about a conference makes it meaningful 🤔]]></title><description><![CDATA[One of the weird and wonderful perks of being in the tech industry is the sheer volume of events available for everyone to attend, whether…]]></description><link>https://blog.andyet.com/2018/05/23/what-about-a-conference-makes-it-meaningful/</link><guid isPermaLink="false">https://blog.andyet.com/2018/05/23/what-about-a-conference-makes-it-meaningful/</guid><pubDate>Wed, 23 May 2018 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the weird and wonderful perks of being in the tech industry is the sheer volume of events available for everyone to attend, whether your interest is broad or tunnel-vision specific. We’ve thrown our fair share of events (&lt;a href=&quot;https://experience.realtimeconf.com/&quot;&gt;RealtimeConf&lt;/a&gt;, &lt;a href=&quot;https://vimeo.com/channels/417706/videos&quot;&gt;RedisConf&lt;/a&gt;, &lt;a href=&quot;http://andyetconf.com/&quot;&gt;&amp;#x26;yetconf&lt;/a&gt;, to name a few) and others on our team have been organizers of events around the globe.&lt;/p&gt;
&lt;p&gt;Recently, our teammate &lt;a href=&quot;https://andyet.com/team/lynn&quot;&gt;Lynn Fisher&lt;/a&gt; suggested we discuss what makes a conference meaningful.&lt;/p&gt;
&lt;h2 id=&quot;what-are-some-examples-of-great-conferences-youve-been-to-who-executed-things-well&quot;&gt;&lt;a href=&quot;#what-are-some-examples-of-great-conferences-youve-been-to-who-executed-things-well&quot; aria-label=&quot;what are some examples of great conferences youve been to who executed things well permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What are some examples of great conferences you’ve been to who executed things well?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Lynn Fisher&lt;/strong&gt;, Designer, Developer&lt;br&gt;
I went to &lt;a href=&quot;https://aneventapart.com/&quot;&gt;An Event Apart&lt;/a&gt; in 2010 and it made a &lt;em&gt;huge&lt;/em&gt; impact on my work. That event runs like a well-oiled machine and consistently has excellent speakers and content.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://braziljs.org/conf/&quot;&gt;JSConf Brazil&lt;/a&gt; in 2014 pulled off an awesome one-day event with live audio translation between English and Portuguese, which I was super impressed with.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.cssdevconf.com/&quot;&gt;CSSDevConf&lt;/a&gt; did something kind of unique with their multiple track format (I usually prefer single track). Attendees can vote on talks they found valuable and a group of those speakers present &lt;em&gt;again&lt;/em&gt; later on. I was able to catch some talks that I’d missed because of competing time slots.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://andyetconf.com/&quot;&gt;&amp;#x26;yetConf&lt;/a&gt; is unmatched in my mind in creating a unique and surprising conference experience that was exciting, personal, and challenging.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Karolina Szczur&lt;/strong&gt;, Designer, Developer&lt;br&gt;
I had the best experience at inclusive events such as &lt;a href=&quot;https://2018.cssconf.eu/&quot;&gt;CSSConf&lt;/a&gt; and &lt;a href=&quot;https://www.jsconf.eu/&quot;&gt;JSConf&lt;/a&gt; Europe and &lt;a href=&quot;http://nordic.js/&quot;&gt;Nordic.js&lt;/a&gt; in Stockholm. They went to incredible lengths to challenge the status quo and assumptions about how a technical conference should look like—fun, welcoming, teaching, community and people-first.&lt;/p&gt;
&lt;h2 id=&quot;what-assumed-conference-must-haves-really-arent-and-should-be-done-differently&quot;&gt;&lt;a href=&quot;#what-assumed-conference-must-haves-really-arent-and-should-be-done-differently&quot; aria-label=&quot;what assumed conference must haves really arent and should be done differently permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What assumed conference “must-haves” really aren’t and should be done differently?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Lynn&lt;/strong&gt;&lt;br&gt;
Speaker Q+A and panels. In my experience it’s rarely a good use of the time and often results in a few speakers dominating the conversation. And let’s eliminate the opportunity for dudes to stand up and ask “a question, but kind of a comment.”&lt;/p&gt;
&lt;p&gt;Multiple tracks. As I mentioned, I’m a huge fan of the single track. With multiple tracks people tend to select the talks that most directly apply to their work. But some of the best talks I’ve seen are ones I was surprised by, unsure of whether it would apply. Spoiler: they always do. And, experiencing the conference as one big group is actually a neat thing.&lt;/p&gt;
&lt;p&gt;Hour-long talks. 20-30 minutes is plenty of time for the majority of speakers and content. It encourages speakers to edit and allows for more speakers in the day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adam Brault&lt;/strong&gt;, Founder, CEO&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Panels are an abomination.&lt;/li&gt;
&lt;li&gt;Q&amp;#x26;A is worthless.&lt;/li&gt;
&lt;li&gt;Alcohol is totally unnecessary and generally the opposite of a valuable addition to the experience.&lt;/li&gt;
&lt;li&gt;No one really needs a talk longer than 15 minutes. (Even longwinded people like me!)&lt;/li&gt;
&lt;li&gt;Talks are not the only meaningful thing that can be done at a conference. (See &lt;a href=&quot;http://2017.ull.ie/&quot;&gt;Ùll’s&lt;/a&gt; “installations” and talk show interviews, &lt;a href=&quot;https://2018.jsconf.us/&quot;&gt;JSConf US’s&lt;/a&gt; middle day outings, and &lt;a href=&quot;https://affectconf.com/&quot;&gt;AffectConf’s&lt;/a&gt; volunteer day.)&lt;/li&gt;
&lt;li&gt;Most social events are not designed to facilitate true sociality, they are designed to create a party feel. Good social connections actually happen through smaller groups and one-on-one discussions.&lt;/li&gt;
&lt;li&gt;And let’s talk about name badges. Nice aesthetically pleasing name tags are more user friendly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-small-details-make-a-big-difference&quot;&gt;&lt;a href=&quot;#what-small-details-make-a-big-difference&quot; aria-label=&quot;what small details make a big difference permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What small details make a big difference?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Karolina&lt;/strong&gt;&lt;br&gt;
Carefully crafted, non-sponsor branded, environmentally friendly swag. Healthy food catering to dietary requirements. All gender bathrooms. De-emphasising the presence of alcohol. Pronoun stickers. Women-fit t-shirts. The availability of quiet spaces.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lynn&lt;/strong&gt;&lt;br&gt;
I look for the things organizers didn’t need to do, but show they thought about their attendees as people. A few that stick out to me are: gender-neutral bathrooms, sanitary supplies in the bathrooms, allergy-aware food options, alternatives for non-drinkers, childcare during the conference, and live captioning/translations for talks.&lt;/p&gt;
&lt;p&gt;Personalized swag and curated swag boxes (not sticking random branded stuff in a bag) make a conference feel extra special.&lt;/p&gt;
&lt;p&gt;A well-scheduled event is huge and can be hard to get right. Are the breaks frequent and how do you know when to return? Are the talks too long and too many grouped together? Is there an emcee to lead attendees into each new part of the schedule?&lt;/p&gt;
&lt;p&gt;Small details for speakers could be its own blog post, but one I’ll mention is handing your speakers a bottle or glass of water as their time slot approaches. Huge.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adam&lt;/strong&gt;&lt;br&gt;
I learned this one in a BIG way. At &lt;a href=&quot;https://andyet.com/team/karolina&quot;&gt;Karolina’s&lt;/a&gt; suggestion we offered captioning at &amp;#x26;yetConf. As a result, we not only had deaf attendees, we also had some of the most hilarious moments interacting with the captioner, and one of the best conference talks.&lt;/p&gt;
&lt;p&gt;As a result, whenever we are talking about sponsoring a conference, we always try to encourage the conference to add captioning and sponsor that.&lt;/p&gt;
&lt;h2 id=&quot;who-are-people-youve-learned-from-about-conference-design&quot;&gt;&lt;a href=&quot;#who-are-people-youve-learned-from-about-conference-design&quot; aria-label=&quot;who are people youve learned from about conference design permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Who are people you’ve learned from about conference design?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Karolina&lt;/strong&gt;&lt;br&gt;
&lt;a href=&quot;https://twitter.com/ashedryden&quot;&gt;Ashe Dryden&lt;/a&gt; created invaluable materials on running inclusive events and governance, setting a shining example with &lt;a href=&quot;https://alterconf.com/&quot;&gt;AlterConf&lt;/a&gt;. I was always inspired by how &lt;a href=&quot;https://twitter.com/andymcmillan&quot;&gt;Andy McMillan&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/waxpancake&quot;&gt;Andy Baio&lt;/a&gt; have challenged the format of conferences with &lt;a href=&quot;https://2018.xoxofest.com/&quot;&gt;XOXO&lt;/a&gt;. Last but not least, experience design by CSSConf and JSConf Europe teams (especially &lt;a href=&quot;https://twitter.com/kriesse&quot;&gt;Kristina Schneider&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/janl&quot;&gt;Jan Lehnardt&lt;/a&gt;)—they&apos;ve crafted something on an entirely different level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lynn&lt;/strong&gt;&lt;br&gt;
I’ve learned a lot from observing &lt;a href=&quot;https://andyet.com/team/adam&quot;&gt;Adam&lt;/a&gt;, &lt;a href=&quot;http://www.jennavievefilms.com/&quot;&gt;Jenna&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/jenn&quot;&gt;Jenn&lt;/a&gt;, and &lt;a href=&quot;https://andyet.com/team/amy&quot;&gt;Amy&lt;/a&gt; as they prepared things for &amp;#x26;yetConf. They’ve definitely modeled the unique and personal conference experience, where doing that extra work truly makes things magical.&lt;/p&gt;
&lt;p&gt;Karolina has been sharing a lot of her thoughts and learnings about creating diverse and inclusive events and that’s been eye-opening too!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adam&lt;/strong&gt;&lt;br&gt;
Let me start by saying that for most of the past 20 years, I have been slowly growing in my understanding of systemic racism, sexism, and ableism—most especially including my own. I am embarrassed that the first technical conference I organized had 42(!!) speakers and only two of them were women.&lt;/p&gt;
&lt;p&gt;I am personally fascinated by the ability of a conference to have an intentional shaping influence on the culture of the industry. No conference has had the impact of JS Conf EU, which is probably the most pioneering conference in creating an inclusive and diverse tech conference.&lt;/p&gt;
&lt;p&gt;To that end, I give props to &lt;a href=&quot;https://twitter.com/theophani&quot;&gt;Tiffany Conroy’s&lt;/a&gt; foundational influence on JSConf EU, and Karolina Szczur’s continued advancement of those ideals both through [JS,CSS]Conf[EU,AU] has been extremely inspiring and educational. &lt;a href=&quot;https://twitter.com/janl&quot;&gt;Jan Lehnardt&lt;/a&gt; and the rest of the EU team no doubt deserve credit, but I know that Tiffany’s &lt;em&gt;&lt;a href=&quot;http://weareallaweso.me/&quot;&gt;We Are All Awesome&lt;/a&gt;&lt;/em&gt; project and her thoughts on what was possible for representation at conferences was mind opening for me.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/voodootikigod&quot;&gt;Chris Williams&lt;/a&gt; deserves significant credit for setting the tone for open collaboration and unwavering support for baby tech conferences, bringing a spirit of open source generosity and kindness that has been a hallmark among conference organizers toward other conference organizers in the JavaScript community.&lt;/p&gt;
&lt;p&gt;I was always intrigued to see the approaches that &lt;a href=&quot;https://twitter.com/mikeal&quot;&gt;Mikeal Rogers&lt;/a&gt; took to conference organizing in the &lt;a href=&quot;http://nodeconf.com/&quot;&gt;NodeConf&lt;/a&gt; series, as it always seemed to be what he believed was best for the community at that particular moment, evolving the conference from a technical exhibition to an educational, community building and onboarding experience.&lt;/p&gt;
&lt;p&gt;I once said &lt;a href=&quot;https://twitter.com/paulca&quot;&gt;Paul Campbell&lt;/a&gt; was “the kind Steve Jobs of conferences” and I stand by that. I’ve learned some of the most unique lessons from his event design, two of which being the importance of creating a unique shared experience, and ways to create a conference experience that works for introverts.&lt;/p&gt;
&lt;p&gt;Along with Paul, Jesse White and &lt;a href=&quot;https://twitter.com/ajleon&quot;&gt;AJ Leon&lt;/a&gt; taught me how a conference can be a truly magical communal experience.&lt;/p&gt;
&lt;p&gt;I also have learned a lot from teammates I collaborated with on conferences. From Mel, I learned that basically anything is possible and we shouldn’t give up just because an idea is hard to pull off. From Jenna, I learned that it was possible to have fun and laugh about it even when discouraged as hell and use that sense of humor to keep driving forward and making the best event we could even if it didn’t match the ideal in our heads. From Jenn and Amy, I learned that having an organized plan for communication, structure, roles and responsibilities helps everyone involved want to kill you just a little bit less. :grimacing:&lt;/p&gt;
&lt;h2 id=&quot;what-events-are-you-looking-forward-to-attending&quot;&gt;&lt;a href=&quot;#what-events-are-you-looking-forward-to-attending&quot; aria-label=&quot;what events are you looking forward to attending permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What events are you looking forward to attending?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Karolina&lt;/strong&gt;&lt;br&gt;
I’m always excited about going back to JSConf and CSSConf Europe held in Berlin. Those two events have become the golden standard for tech conferences worldwide. They also feel like a family reunion, especially that I’ve attended every single edition prior.&lt;/p&gt;
&lt;p&gt;I’m planning to finally make it to &lt;a href=&quot;https://2018.xoxofest.com/&quot;&gt;XOXO&lt;/a&gt; in Portland, a fantastic festival for creatives run by a friend of mine, &lt;a href=&quot;https://twitter.com/andymcmillan&quot;&gt;Andy McMillan&lt;/a&gt;, and Andy Baio.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lynn&lt;/strong&gt;&lt;br&gt;
The &amp;#x26;yet design team is attending &lt;a href=&quot;https://aneventapart.com/event/boston-2018&quot;&gt;An Event Apart in Boston&lt;/a&gt; this June. I’m thrilled to go after attending for the first time 8 years ago. There’s so much that excites me about the web right now and taking a CSS workshop with &lt;a href=&quot;https://twitter.com/meyerweb&quot;&gt;Eric Meyer&lt;/a&gt; feels like the dream.&lt;/p&gt;
&lt;p&gt;I’m also going to be speaking at &lt;a href=&quot;https://phxdw.com/&quot;&gt;Phoenix Design Week&lt;/a&gt; this year (baby’s first keynote). I’ve been attending for years and I’m super excited about the theme this year. It’s focused on “Beyond Design” and exploring how other industries, disciplines, and perspectives affect the past and where we’re going. It’s right up my alley.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adam&lt;/strong&gt;&lt;br&gt;
I am completely and totally exhausted by events that I don’t produce and I am completely and totally exhausted by events that I produce. However, I was impressed by &lt;a href=&quot;https://affectconf.com/&quot;&gt;AffectConf&lt;/a&gt; last year in having a lineup of people I’d never been exposed to who shared challenging talks that would have made for riveting keynotes at any conference I’d attended. Planning on that one for sure.&lt;/p&gt;
&lt;br&gt;
There are at least 30 more questions we could keep discussing (seriously, Adam wrote out *at least* that many) our opinions on what makes a conference not only a success, but worth attending. We want to know what you think about conferences? Which ones are you looking forward to this year? Send us your replies at [@andyet](https://twitter.com/andyet) on Twitter, or questions and we’ll keep this conversation going.</content:encoded></item><item><title><![CDATA[Voyage across the Clouds with Kubernetes]]></title><description><![CDATA[In the DevOps world, Kubernetes is kind of a big deal. Since 2014, when development first began, Kubernetes has become the preeminent…]]></description><link>https://blog.andyet.com/2018/05/17/voyage-across-the-clouds-with-k8s/</link><guid isPermaLink="false">https://blog.andyet.com/2018/05/17/voyage-across-the-clouds-with-k8s/</guid><pubDate>Thu, 17 May 2018 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/65e3685d2acca34fe714aaaf70186f48/1cfc2/cloud-voyage.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 55.62913907284768%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABQUlEQVQoz2WRPU7EMBCFczrOwDGoqKk5CAU1HRItFEiIbqWlSGxn2QUEu+v8OfbM8GIn+xu9wnbme555znQVklQVcjtITSejbBSLdjwsUrENhQ1Z2hSR+Wnpu6VktCc9gzSvSz371d3Ag1zUQ3GWyFVDLEIigaUjMXUiParzt1V59Wgu7vKHuRYpNt72KBTUZ6mHZUMuCAxwtO15vHbjjUh++/yRXc8u7w2MLEiUSBt4hNPlUFlTWY8jqNReQ6bl95un+YsuYbT2lWdHEu+e4F1myo55YHjP6IKKijQG6QhTxCzIeh6GPIEhM7kgD/yuei5sHD6Sasp5UdNXCmzXZHotLMwUuLJ730UTPpuDHqv4VChF9Jueu8B/jmGpjrGkrSOkZQ5OMhT1aYKDzxEjuXPeHG+Hm09YeOEd1o7yM/hE/4fubVOgxRJ2AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;A Talky rocket flying amongst the clouds&quot;
        title=&quot;&quot;
        src=&quot;/static/65e3685d2acca34fe714aaaf70186f48/90cbd/cloud-voyage.png&quot;
        srcset=&quot;/static/65e3685d2acca34fe714aaaf70186f48/29fe9/cloud-voyage.png 151w,
/static/65e3685d2acca34fe714aaaf70186f48/6728c/cloud-voyage.png 303w,
/static/65e3685d2acca34fe714aaaf70186f48/90cbd/cloud-voyage.png 605w,
/static/65e3685d2acca34fe714aaaf70186f48/1cfc2/cloud-voyage.png 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the DevOps world, &lt;a href=&quot;https://kubernetes.io/&quot;&gt;Kubernetes&lt;/a&gt; is kind of a big deal. Since 2014, when development first began, Kubernetes has become the preeminent container orchestration tool for running containerized applications on the web. When I joined &amp;#x26;yet in 2016, I was new to the world of DevOps, but since then I’ve had the opportunity to use Kubernetes on four different cloud platforms: &lt;a href=&quot;https://www.packet.net/&quot;&gt;Packet&lt;/a&gt;, &lt;a href=&quot;https://aws.amazon.com/&quot;&gt;Amazon Web Services&lt;/a&gt; (AWS), &lt;a href=&quot;https://azure.microsoft.com/en-us/&quot;&gt;Microsoft Azure&lt;/a&gt;, and &lt;a href=&quot;https://cloud.google.com/&quot;&gt;Google Cloud&lt;/a&gt;. That experience has demonstrated the consistent power of Kubernetes across different platforms and the freedom it give teams to change providers as cloud technology evolves.&lt;/p&gt;
&lt;p&gt;One of my major realizations about working in DevOps is that technology is moving FAST. It has been less than six month since the Cloud Native Computing Foundation launched their &lt;a href=&quot;https://www.cncf.io/announcement/2017/11/13/cloud-native-computing-foundation-launches-certified-kubernetes-program-32-conformant-distributions-platforms/&quot;&gt;certified Kubernetes program&lt;/a&gt; and Microsoft, Amazon, and Google have all launched managed Kubernetes solutions in the interim. (If you’re interested to know the origin of the “k8s” abbrev check out this &lt;a href=&quot;https://medium.com/@rothgar/why-kubernetes-is-abbreviated-k8s-905289405a3c&quot;&gt;Medium post by @rothgar&lt;/a&gt;.) I’ve deployed the services that power &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; across multiple providers and wanted to share that experience with you! The choice to use k8s as our primary orchestration tool has given our team the ability to maximize the strengths of different cloud providers and choose the best provider for a given endeavor.&lt;/p&gt;
&lt;p&gt;Kubernetes is a versatile tool designed by some great folks* and backed by a &lt;a href=&quot;https://kubernetes.io/community/&quot;&gt;thriving open-source community&lt;/a&gt;. Unfortunately, there is a fairly substantial learning curve for most folks picking up k8s for the first time. In this post, I won’t go into the k8s architecture or how to get started with it, since there are many &lt;a href=&quot;https://www.youtube.com/results?search_query=kubernetes+101&quot;&gt;great videos&lt;/a&gt; on that topic freely available. If you learn best by doing, check out &lt;a href=&quot;http://kubernetesbyexample.com/&quot;&gt;Kubernetes By Example&lt;/a&gt; by the OpenShift Team, or for a deeper dive try &lt;a href=&quot;https://github.com/kelseyhightower/kubernetes-the-hard-way/&quot;&gt;Kubernetes The Hard Way&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/kelseyhightower&quot;&gt;Kelsey Hightower&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;packet&quot;&gt;&lt;a href=&quot;#packet&quot; aria-label=&quot;packet permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Packet&lt;/h2&gt;
&lt;p&gt;My first experience of Kubernetes was in 2016 with a CoreOS cluster hosted on &lt;a href=&quot;https://www.packet.net/&quot;&gt;Packet&lt;/a&gt; running version 1.2.2. Our Ops team configured the cluster with a lengthy cloud-config file which included etcd settings, systemd files, SSL files, and YAML manifests for the master services. It worked, but updating anything was a massive pain; so painful in fact, it was easier to build an entirely new cluster instead of trying to upgrade nodes beyond version 1.2 as they became available. Thanks to the meteoric growth of DevOps technology in the past several years there are now &lt;a href=&quot;https://help.packet.net/solutions/platforms/kubernetes&quot;&gt;better solutions&lt;/a&gt; to running k8s on Packet. We still think that Packet is awesome, especially since they increased the number and variety of &lt;a href=&quot;https://www.packet.net/bare-metal/servers/&quot;&gt;offerings&lt;/a&gt; over the past year.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9002e4ca10a951aeb8ae50b3ff23d0c1/1cfc2/yeti-cloud-hug.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 55.62913907284768%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABPElEQVQoz32SvU7DMBDH+1y8AgtPwxMwICaegKViYGFBYgCJiY+BDQkUqaVN7KRNP0KburET+3xX2wjRIhrpr5Nt3e/8P/s6fA07EpAa5AaZi+FkKCAR8DctqLOzXxmO1L/6YAcX49vPRFO6hlJTLq3j03aYrUwGVNwPeofd6Kg7EaZQulEKkXKiRHpf++E1CINEJMHmRak0DpbyJplM51X9NotzyaXd5n9hZ2yqLHiWIp73xjO3mBd1dP66vBvKsxf+mHFLvrV9MAbYADQaGqKiv1DXEVoEoqwC1m5buzwkV8FYWjZYa1u4bk+e5OnziIiVZi/sLhfaw5VBY7EGSkvInPnLd3n84N+sBWYhSuO9Oy0a/KpDLUBrcaIwbrHt+TAS8xrd336njiqb+AixaB+SH8WhRLplh/2XtgHJaGkDp0SGWgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;An &amp;yet yeti hugging a cloud wearing a K8s hat&quot;
        title=&quot;&quot;
        src=&quot;/static/9002e4ca10a951aeb8ae50b3ff23d0c1/90cbd/yeti-cloud-hug.png&quot;
        srcset=&quot;/static/9002e4ca10a951aeb8ae50b3ff23d0c1/29fe9/yeti-cloud-hug.png 151w,
/static/9002e4ca10a951aeb8ae50b3ff23d0c1/6728c/yeti-cloud-hug.png 303w,
/static/9002e4ca10a951aeb8ae50b3ff23d0c1/90cbd/yeti-cloud-hug.png 605w,
/static/9002e4ca10a951aeb8ae50b3ff23d0c1/1cfc2/yeti-cloud-hug.png 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In early 2017 we made the decision as an Ops team to embrace managed cloud solutions. As a small team we don’t manage any physical servers on-prem, so the decision to rely on cloud solutions has freed up our team to spend more time optimizing our DevOps processes and less time maintaining servers.&lt;/p&gt;
&lt;h2 id=&quot;aws&quot;&gt;&lt;a href=&quot;#aws&quot; aria-label=&quot;aws permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS&lt;/h2&gt;
&lt;p&gt;Since we already used AWS, one of the first tools we tried was &lt;a href=&quot;https://github.com/kubernetes/kops&quot;&gt;kops&lt;/a&gt;. True to its unofficial(?) tagline of “kubectl for clusters”, kops lets you create and maintain k8s clusters from the command line. Once your AWS IAM permission and DNS settings are are set up correctly (spoiler alert: not a trivial endeavor) you can spin up a k8s cluster in just a few commands. kops is still under active development and it now has beta support for Google Compute Engine (GCE) and early stage support for DigitalOcean, OpenStack, and VMware vSphere. Although kops is an effective way to manage Kubernetes clusters, it still required a fair bit of manual configuration before it was usable. We thought there had to be something better out there.&lt;/p&gt;
&lt;p&gt;AWS is a powerful platform and it arguably has the most product offerings of any major cloud providers, but they were slightly behind-the-times when it came to Kubernetes. AWS announced their managed k8s solution, &lt;a href=&quot;https://aws.amazon.com/eks/&quot;&gt;Elastic Container Service for Kubernetes&lt;/a&gt; (EKS), just a few weeks after &lt;a href=&quot;https://azure.microsoft.com/en-us/blog/introducing-azure-container-service-aks-managed-kubernetes-and-azure-container-registry-geo-replication/&quot;&gt;Microsoft Azure&lt;/a&gt; and &lt;a href=&quot;https://cloudplatform.googleblog.com/2017/11/introducing-Certified-Kubernetes-and-Google-Kubernetes-Engine.html&quot;&gt;Google Cloud Platform&lt;/a&gt;. Because the other providers launched managed k8s first, we moved on to try Azure and GCP. Read on to hear of our adventures voyaging through these new lands!&lt;/p&gt;
&lt;h2 id=&quot;azure&quot;&gt;&lt;a href=&quot;#azure&quot; aria-label=&quot;azure permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Azure&lt;/h2&gt;
&lt;p&gt;After a brief trial with kops we decided to give Azure a chance as we were intrigued by reports of &lt;a href=&quot;https://www.rightscale.com/blog/cloud-cost-analysis/comparing-cloud-instance-pricing-aws-vs-azure-vs-google-vs-ibm&quot;&gt;slightly lower prices&lt;/a&gt; compared to their competitors. Sadly, we moved to Azure just two months ahead of their announcement of managed Kubernetes (AKS), so we haven’t yet tried it. Even using Azure Container Services, the predecessor to AKS, the process of building a k8s cluster on Azure was surprisingly pleasant. We had a cluster going quickly and were able to start migrating services from our old cluster right away. Although the set up was fairly smooth, within a few months of running production services on Azure, we encountered limitations of their platform that necessitated a weird hack to &lt;code class=&quot;language-text&quot;&gt;iptables&lt;/code&gt; and a separate incident caused by VMs rebooting unexpectedly overnight. These issues, along with the profusion of legacy services that still exist in the Azure stack prompted us to abandon Azure after only three months. My impression is that Microsoft is continuing to develop their support for Kubernetes, as evidenced by their acquisition of &lt;a href=&quot;https://deis.com/blog/2017/deis-to-join-microsoft/&quot;&gt;Deis Workflow&lt;/a&gt; in early-2017, and their support of a neat k8s sandboxing tool called &lt;a href=&quot;https://github.com/Azure/draft&quot;&gt;Draft&lt;/a&gt;. Azure offerings have evolved in the past few months, and some of our negative experiences may have just been due to poor timing.&lt;/p&gt;
&lt;h2 id=&quot;google-cloud&quot;&gt;&lt;a href=&quot;#google-cloud&quot; aria-label=&quot;google cloud permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Google Cloud&lt;/h2&gt;
&lt;p&gt;The final leg of our voyage across the clouds led our team to adopt Google Cloud Platform. We had already been trialing Google Kubernetes Engine (GKE) for a subset of services, and were extremely impressed. Spinning up a cluster takes about 5 minutes (actually tho) and we got things migrated in less than a week. As a new user, I have been delighted by GCP’s clean, intuitive web GUI, and CLI. We’ve been running k8s services on GKE for about 6 months now and have been very happy. Kubernetes was originally designed by former Googlers so I’m glad to see how seamlessly GCP has integrated k8s into their Compute Engine service.&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;&lt;a href=&quot;#final-thoughts&quot; aria-label=&quot;final thoughts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;My experience with four major cloud providers in the past year has been an educational journey to say the least. We made decisions about transitioning between cloud providers based on our needs, ease of use, and state of the technology at a given time. It is clear to anyone following the growth of DevOps technology that it’s not going to slow down any time soon. The best available solutions will likely evolve and change on a monthly, and in some cases even a daily basis! We’ve seen eight major releases of Kubernetes since I joined the world of DevOps and it seems like every day there’s a new blog post or announcement about k8s from a major player in this space. While we’ve arrived at a good place for our Ops needs right now, the voyage is far from over.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;*former Googlers Joe Beda, Craig McLuckie, and Brendan Burns&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What I recently learned about leadership]]></title><description><![CDATA[A few months ago I became a team lead. It was a pretty unexpected role shift. I’d always considered myself more of a worker bee than a…]]></description><link>https://blog.andyet.com/2018/05/16/what-I-recently-learned-about-leadership/</link><guid isPermaLink="false">https://blog.andyet.com/2018/05/16/what-I-recently-learned-about-leadership/</guid><pubDate>Wed, 16 May 2018 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A few months ago I became a team lead. It was a pretty unexpected role shift. I’d always considered myself more of a worker bee than a leader. When the opportunity was presented to me, I didn’t let the idea sink in very long before I said ‘yes.’ Only I didn’t really say ‘yes.’ I said something like ‘Well, there are a &lt;em&gt;few&lt;/em&gt; things about that role that I feel I might be good at, and &lt;em&gt;lots&lt;/em&gt; of things that I’ll definitely need to learn.’ Luckily that passes for a ‘yes’ at &amp;#x26;yet, and I was henceforth the Design Team Lead.&lt;/p&gt;
&lt;p&gt;Then I panicked.&lt;/p&gt;
&lt;p&gt;Here are a few of the fears that were swirling through my head:&lt;/p&gt;
&lt;h2 id=&quot;-im-too-pragmatic-and-risk-averse-in-a-team-full-of-big-thinkers&quot;&gt;&lt;a href=&quot;#-im-too-pragmatic-and-risk-averse-in-a-team-full-of-big-thinkers&quot; aria-label=&quot; im too pragmatic and risk averse in a team full of big thinkers permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;😰 I’m too pragmatic and risk-averse in a team full of big thinkers…&lt;/h2&gt;
&lt;p&gt;&amp;#x26;yet as a company has built its identity on thinking outside the box, taking risks, solving things in really unconventional ways, and I guess just bucking the system in a way. I’d always felt a bit insecure in my propensity toward worry, overthinking, and pragmatism. I actually &lt;em&gt;like&lt;/em&gt; systems. Am I even capable of making decisions that align with the company’s values?&lt;/p&gt;
&lt;h2 id=&quot;-how-do-you-even-lead-leaders&quot;&gt;&lt;a href=&quot;#-how-do-you-even-lead-leaders&quot; aria-label=&quot; how do you even lead leaders permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;😰 How do you even lead &lt;em&gt;leaders&lt;/em&gt;…?&lt;/h2&gt;
&lt;p&gt;One of the most intimidating things about this role is the fact that the &amp;#x26;yet design team is amazing. Every single person is really accomplished. Every member of the team is a leader in some capacity; of big complex projects, of ways of thinking about tech culture, of design approaches, of mind-bending ways of using CSS. What value could I possibly bring to this role that everyone wasn’t already bringing to the team in spades?&lt;/p&gt;
&lt;h2 id=&quot;-what-if-i-make-a-mistake&quot;&gt;&lt;a href=&quot;#-what-if-i-make-a-mistake&quot; aria-label=&quot; what if i make a mistake permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;😰 What if I make a mistake…?&lt;/h2&gt;
&lt;p&gt;What if I miscalculate, miscommunicate, misinterpret, miss a meeting, miss an email, miss a &lt;em&gt;detail&lt;/em&gt;? What. If. I. &lt;strong&gt;FAIL&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;Hello, hi folks. 👋&lt;/p&gt;
&lt;p&gt;It’s been, oh gosh…6 months-ish. And guess what? I haven’t failed. Not even close. I have made mistakes, cried in front of my teammates 😳, and missed &lt;em&gt;plenty&lt;/em&gt; of details. I’ve also seen the team flourish, maintain its soul, do amazing work, score major wins, and even grow in number!&lt;/p&gt;
&lt;p&gt;It’s safe to say I’ve learned a &lt;em&gt;ton&lt;/em&gt; in the past few months. I’ve grown personally in many ways, and have received support and wisdom from so many people. Much of what I’ve learned has been through trial by fire; just diving in, coping, figuring things out as I go, and (occasionally when I muster up the courage) trusting my gut. But I still have a long way to go.&lt;/p&gt;
&lt;p&gt;It hasn’t been until pretty recently that I’ve had the mental space to reach out to the wider world and seek out what others have to say about leadership. A few weeks ago my coworking space hosted a &lt;a href=&quot;http://elevateleaders.co/&quot;&gt;conference&lt;/a&gt; for leaders in tech. I waffled back and forth for a while before I finally signed up to attend. I’m an introvert for one, so I really have to psyche myself up to go to a conference. And honestly I was pretty skeptical, thinking that I’d get a lot of really eye-rolley, corporate, blanket advice on Leadership with a capital L.&lt;/p&gt;
&lt;p&gt;I’ve never taken so many notes in my life.&lt;/p&gt;
&lt;p&gt;To my surprise, I got a ton out of it. Turns out, leadership is hard for &lt;em&gt;everyone&lt;/em&gt;. But there are a lot of really great, really relatable people out there who have amazing things to say about it.&lt;/p&gt;
&lt;p&gt;Here are a few things that stood out to me:&lt;/p&gt;
&lt;h2 id=&quot;🤯-if-you-have-a-tendency-toward-perfectionism-it-affects-your-team&quot;&gt;&lt;a href=&quot;#%F0%9F%A4%AF-if-you-have-a-tendency-toward-perfectionism-it-affects-your-team&quot; aria-label=&quot;🤯 if you have a tendency toward perfectionism it affects your team permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🤯 If you have a tendency toward perfectionism, it affects your team.&lt;/h2&gt;
&lt;p&gt;Maybe this seems obvious? I don’t know about you, but I’ve always considered my perfectionism to be a personal trait, affecting only tasks that I personally was working on. One of the most impactful talks for me at the conference was &lt;a href=&quot;https://twitter.com/llergies&quot;&gt;Colin Flanigan’s&lt;/a&gt; talk about being a perfectionist as a leader.&lt;/p&gt;
&lt;p&gt;He pointed out that perfectionists have a tendency to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Waffle on decisions&lt;/li&gt;
&lt;li&gt;Misinterpret confidence&lt;/li&gt;
&lt;li&gt;Cling to broken tools/systems/ideas&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s true these symptoms of perfectionism have a far wider reach than my individual projects. It’s easy to see how these would affect a team.&lt;/p&gt;
&lt;h2 id=&quot;🤯-know-the-difference-between-burnout-and-depression&quot;&gt;&lt;a href=&quot;#%F0%9F%A4%AF-know-the-difference-between-burnout-and-depression&quot; aria-label=&quot;🤯 know the difference between burnout and depression permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🤯 Know the difference between burnout and depression.&lt;/h2&gt;
&lt;p&gt;I didn’t really know that I didn’t know this…if that makes sense. My understanding was a bit hand-wavey before, but a key misunderstanding I had (as evidenced by &lt;a href=&quot;https://twitter.com/DesignSaves/status/971843382615072768&quot;&gt;this tweet&lt;/a&gt;) was that burnout can be caused by anything in life. &lt;a href=&quot;https://twitter.com/zenfounder&quot;&gt;Dr. Sherry Walling’s&lt;/a&gt; discussion at the conference actually taught me that the main difference between burnout and depression is that burnout is &lt;em&gt;inextricably&lt;/em&gt; caused by your work. And because burnout and depression have a different cause, they have different intervention methods.&lt;/p&gt;
&lt;p&gt;While burnout tends to feel and look a lot like regular depression, it can also bring along unique symptoms, like the feeling of a lack of efficacy, and cynical detachment from your work. This is something I’m really interested in learning more about. It’s a huge priority for me as a leader to learn to recognize burnout in myself and others and do whatever is in my power to prevent it.&lt;/p&gt;
&lt;h2 id=&quot;🤯-theres-a-difference-between-having-values-and-living-values&quot;&gt;&lt;a href=&quot;#%F0%9F%A4%AF-theres-a-difference-between-having-values-and-living-values&quot; aria-label=&quot;🤯 theres a difference between having values and living values permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;🤯 There’s a difference between &lt;em&gt;having&lt;/em&gt; values and &lt;em&gt;living&lt;/em&gt; values.&lt;/h2&gt;
&lt;p&gt;Sometimes at conferences I get asked “What makes &amp;#x26;yet unique?”…or questions to that effect. A lot of things that come to mind are characteristic of our team values. We care deeply about what we do, we design and build things with our heads and our hearts, we’re human-focused, we’re &lt;em&gt;people first&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;‘People first’ has gotten to be kind of a popular phrase, I’ve noticed. Many tech companies these days list values that look really quite similar to ours - which is great. They’re great values. But…stating those values no longer answers the question, “What makes &amp;#x26;yet unique?” What makes you unique these days is &lt;em&gt;living&lt;/em&gt; your values. Figuring out ways of doing this authentically may be the hardest thing about being a leader.&lt;/p&gt;
&lt;p&gt;I’m lucky to have mentors at &amp;#x26;yet who care deeply about meaningful leadership. Have you heard of &lt;a href=&quot;https://leadershippy.com/&quot;&gt;Leadershippy&lt;/a&gt;? &lt;a href=&quot;https://andyet.com/team/sarah/&quot;&gt;Sarah Bray&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/adam/&quot;&gt;Adam Brault&lt;/a&gt; and many others at &amp;#x26;yet have worked super hard to create resources for people-first leaders that go way beyond the obvious. I mean &lt;a href=&quot;https://wildling.co/&quot;&gt;&lt;em&gt;way beyond&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I honestly could go on and on. I’m just touching the tip of the iceberg here. I’d love to know what other people have learned, read, and experienced. Please share with &lt;a href=&quot;https://twitter.com/DesignSaves&quot;&gt;me&lt;/a&gt;!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Investigating the ban on Talky in the UAE]]></title><description><![CDATA[Open roadI began my adventure working at &yet in January of 2018, and one of my first experiences was when suddenly, traffic on Talky…]]></description><link>https://blog.andyet.com/2018/05/10/talky-&amp;-uae/</link><guid isPermaLink="false">https://blog.andyet.com/2018/05/10/talky-&amp;-uae/</guid><pubDate>Thu, 10 May 2018 12:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;open-road&quot;&gt;&lt;a href=&quot;#open-road&quot; aria-label=&quot;open road permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Open road&lt;/h2&gt;
&lt;p&gt;I began my adventure working at &amp;#x26;yet in January of 2018, and one of my first experiences was when suddenly, traffic on &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; plummeted. This was particularly jarring to me since one of the reasons I was hired was to be Talky’s product manager. How could traffic drop so quickly, and why didn’t it recover?&lt;/p&gt;
&lt;p&gt;Initially, this felt like a fluke. Perhaps there was an issue with our usage monitoring, or maybe not all of our traffic was being reported? Because we don&apos;t gather data from our users, we didn&apos;t have regional information at our fingertips. Luckily, our support emails began coming in and we were able to diagnose the issue. All of the missing traffic had been coming from one particular country, The United Arab Emirates (UAE), and their government had banned our app.&lt;/p&gt;
&lt;h2 id=&quot;lets-talky-bout-uae&quot;&gt;&lt;a href=&quot;#lets-talky-bout-uae&quot; aria-label=&quot;lets talky bout uae permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let’s Talky ‘bout UAE&lt;/h2&gt;
&lt;p&gt;Why was the UAE using Talky in the first place? They are a small country with a population of only 9.5 million, and their Talky usage was significantly greater than other, much larger countries. The answer is a combination of reasons. The newness of the UAE as a country and need for labor in their domestic oil industry gives them a population that is mostly comprised of expats. This means international communication is a priority for many, and the local telecom regulations do not provide enough options for these residents.&lt;/p&gt;
&lt;p&gt;The United Arab Emirates was formed in 1971 as a federation of seven emirates, or political territories. They are a largely Muslim country that functions with a blend of Western and Sharīʿah laws, principles, and culture. The UAE’s economy is primarily based in energy (oil) with economic diversification efforts in manufacturing and construction. Almost 12 percent of the population living in the UAE is Emirati (citizens of the UAE), while 88.5% (8.5 million people) are expatriates. This statistic is staggering when you consider that the entire United States, with a total population of around 320 million, only has about 4 million expats.&lt;/p&gt;
&lt;h2 id=&quot;license-to-call&quot;&gt;&lt;a href=&quot;#license-to-call&quot; aria-label=&quot;license to call permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;License to call&lt;/h2&gt;
&lt;p&gt;So, there are huge swaths of workers with family in other countries living in the UAE. Why did they all decide to start using Talky? Part of the reason lies with the operating telecom companies. Until 2007, &lt;a href=&quot;http://www.etisalat.com/en/index.jsp&quot;&gt;Etisalat&lt;/a&gt; was the only provider in the country, with the company &lt;a href=&quot;http://www.du.ae/personal&quot;&gt;du&lt;/a&gt; entering the marketplace that year. Only the Telecommunications Regulatory Authority (TRA) has the ability to license to new competitors, and if you &lt;a href=&quot;https://www.tra.gov.ae/en/services-and-activities/licensing/details.aspx#satellite-etisalat2&quot;&gt;look at the licenses granted&lt;/a&gt; you can see they do not do this very often. All public telecom services are provided through these two companies, and their prices reflect the privilege of being licensed. These services can cost up to seven times more in the UAE than in neighboring countries, and international calling is an add-on expense.&lt;/p&gt;
&lt;p&gt;Voice over Internet Protocol (VOIP) apps seem like a perfect solution for those looking to communicate internationally, but many Middle Eastern governments have a negative view of these apps. One of the reasons stated for banning chat apps in the UAE is security. Many of these apps (including Talky) provide end-to-end encryption and are difficult for the government to monitor. After the &lt;a href=&quot;https://en.wikipedia.org/wiki/2016_Turkish_coup_d%27%C3%A9tat_attempt&quot;&gt;attempted coup in Turkey in 2016&lt;/a&gt; was orchestrated over WhatsApp, Middle Eastern governments have been swift to put the hammer down on secure communication platforms. Beginning in 2016, a wave of bans swept across the Middle East for apps like Skype, WhatsApp, Snapchat, and others. Talky was spared in this initial prohibition, but eventually faced the same fate.&lt;/p&gt;
&lt;h2 id=&quot;bringing-it-back&quot;&gt;&lt;a href=&quot;#bringing-it-back&quot; aria-label=&quot;bringing it back permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bringing it back&lt;/h2&gt;
&lt;p&gt;With a short-term economic view, it makes sense for the TRA to keep telecommunications services a majority government-owned duopoly. Limiting competition in this industry may give the government immediate cash-flow, but there are far-reaching consequences. By suppressing competition the UAE indirectly limits innovation in telecom. If new licenses are not given by the TRA, citizens have no incentive to invest their time or money in this industry. Developers and smaller telecom businesses cannot flourish when privacy and independence are not protected. This may not impact the country’s bottom line today, but will limit the potential for future growth in this sector.&lt;/p&gt;
&lt;p&gt;Luckily, the minds of those who create this kind of technology usually move faster than those who regulate it. Virtual private networks, or VPNs, have been widely available for years, and are currently used in the UAE and similar countries to sidestep these bans. In fact, du and Etisalat have their own VPN packages available for subscribers. Additionally, Microsoft and Apple have been working with the government of the UAE to lift its ban on Skype and FaceTime. We hope to bring Talky back to the UAE one day. Until then, we will continue to focus on maintaining the easiest to use and most stable video chat platform for the rest of the world. You can check out &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; and chat with your friends, family, and coworkers for free.&lt;/p&gt;
&lt;h2 id=&quot;references&quot;&gt;&lt;a href=&quot;#references&quot; aria-label=&quot;references permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cleofe Maceda, Senior Web Reporter. (n.d.). &lt;a href=&quot;https://gulfnews.com/guides/tech/individuals-can-access-vpns-in-the-uae-with-caution-1.1872304&quot;&gt;Individuals can access VPNs in the UAE, with caution.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.internations.org/usa-expats/guide/29784-introduction-key-facts/demographics-of-the-us-16552&quot;&gt;Demographics of the US.&lt;/a&gt; (n.d.).&lt;/li&gt;
&lt;li&gt;Naushad K. Cherrayil, Staff Reporter. (n.d.). &lt;a href=&quot;https://gulfnews.com/business/sectors/telecoms/tra-no-need-for-third-telecom-operator-in-uae-1.1001618&quot;&gt;TRA: No need for third telecom operator in UAE.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Radcliffe, D. (2017, December 12). &lt;a href=&quot;https://www.zdnet.com/article/skype-banned-whatsapp-blocked-whats-middle-easts-problem-with-messenger-apps/&quot;&gt;Skype banned, WhatsApp blocked: What’s Middle East’s problem with messenger apps?&lt;/a&gt; | ZDNet.&lt;/li&gt;
&lt;li&gt;ReportBuyer. (2015, October 20). &lt;a href=&quot;https://www.prnewswire.com/news-releases/analysis-of-the-telecom-sector-in-the-united-arab-emirates-2008-2020---growth-trends-and-forecasts-300163369.html&quot;&gt;Analysis of the Telecom sector in The United Arab Emirates (2008-2020) - Growth, Trends and Forecasts.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Turak, N. (2017, July 16). &lt;a href=&quot;https://www.cnbc.com/2018/05/02/microsoft-and-apple-could-get-skype-and-facetime-bans-lifted-in-uae.html&quot;&gt;Microsoft and Apple could get bans on Skype and FaceTime lifted in the UAE.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.globalmediainsight.com/blog/uae-population-statistics/&quot;&gt;UAE Population Statistics in 2018 (Infographics)&lt;/a&gt; | GMI. (n.d.).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.britannica.com/place/United-Arab-Emirates/History&quot;&gt;United Arab Emirates - History.&lt;/a&gt; (n.d.).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.bbc.com/news/world-middle-east-14704414&quot;&gt;United Arab Emirates profile.&lt;/a&gt; (2017, August 29).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bellingcat.com/news/mena/2016/07/24/the-turkey-coup-through-the-eyes-of-its-plotters/&quot;&gt;“We’ve shot four people. Everything’s fine.” The Turkish Coup through the Eyes of its Plotters&lt;/a&gt; - bellingcat. (2017, February 20).&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Background Noise]]></title><description><![CDATA[What media or music helps you work efficiently and stay focused?There are probably as many features about productivity advice on the…]]></description><link>https://blog.andyet.com/2018/05/01/background-noise/</link><guid isPermaLink="false">https://blog.andyet.com/2018/05/01/background-noise/</guid><pubDate>Tue, 01 May 2018 12:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;what-media-or-music-helps-you-work-efficiently-and-stay-focused&quot;&gt;&lt;a href=&quot;#what-media-or-music-helps-you-work-efficiently-and-stay-focused&quot; aria-label=&quot;what media or music helps you work efficiently and stay focused permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What media or music helps you work efficiently and stay focused?&lt;/h2&gt;
&lt;p&gt;There are probably as many features about productivity advice on the internet as there are stars in the sky, grains of sand on the beach, or Kelly Clarkson repeat counts in your music library. So we thought, what the heck, why not add ours? Thus “Background Noise” was born, and we surveyed volunteers from the team to see what sorts of music and media helped them get &lt;em&gt;to&lt;/em&gt; and &lt;em&gt;stay in&lt;/em&gt; a productive mood.&lt;/p&gt;
&lt;h3 id=&quot;what-sounds-do-you-listen-to-to-help-you-focus&quot;&gt;&lt;a href=&quot;#what-sounds-do-you-listen-to-to-help-you-focus&quot; aria-label=&quot;what sounds do you listen to to help you focus permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;em&gt;What sounds do you listen to, to help you focus?&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Amy Lynn Taylor&lt;/strong&gt;, Art Director&lt;br&gt;
For me it really depends on the task at hand. I either need lots of sound or none at all. If I need to focus on any writing or complex problem solving, I might gear up for it with really loud, energetic music (and caffeine) but to actually &lt;em&gt;do&lt;/em&gt; the work, I often need pure quiet. I switch off everything other than white noise, so I can hear my thoughts clearly. If I listen to anything, it would be something instrumental like soft ambient music or &lt;a href=&quot;https://open.spotify.com/user/spotify/playlist/37i9dQZF1DXbrSeoLHavML?si=iytqOYbfQ5SCJFc2_KcXbA&quot;&gt;classical strings&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elliott McNary&lt;/strong&gt;, Front End Developer&lt;br&gt;
This is actually something I think about a lot. Within the past year I’ve really started to focus on what kind of environment keeps me focused on the tasks I need to accomplish and what doesn’t. I’m very sensitive to audio so it plays a really big role in how I work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Eric Zanol&lt;/strong&gt;, Operations&lt;br&gt;
I’ve found that music I’m pretty familiar with is the most helpful to me in being productive, and for some reason, music with singing is better too. The type of music doesn’t seem to matter, I just need to know it well already.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elliott&lt;/strong&gt;&lt;br&gt;
I’ve also noticed that my music choices are very mood-based. While I can listen to most everything, during the work day there are two key factors to the tunes that keep me focused.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If it’s a new song that I haven’t heard before it can’t have words/lyrics.&lt;/li&gt;
&lt;li&gt;If it’s a song with lyrics I need to have them memorized.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When I listen to music while I work I’ve noticed that I am both actively listening and working at the same time. It’s not passive. Music without lyrics enables me to focus on just beeps, boops, clicks, and clacks instead of language and the meaning of that language. Songs with lyrics that I’ve memorized don’t take my mind off a task to think about what the heck the artist said (I listen to a lot of “mumble rap”) and/or what they meant by it. I can just sing (yell) along and not think about it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lynn Fisher&lt;/strong&gt;, Designer, Developer&lt;br&gt;
When I’m working on an illustration or writing CSS, I find I’m super productive when I listen to soundtracks for stage and movie musicals or my Disney songs playlist. I need something upbeat and poppy to get the creativity going. I’m not sure if I need songs that tell stories, but I do like songs I can sing along to while I work.&lt;/p&gt;
&lt;p&gt;When in writing mode though, I need it to be pretty quiet. I’ll play and pause reruns of some of my favorite shows in between bursts of writing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Amy&lt;/strong&gt;&lt;br&gt;
However, if I’m focusing on something purely visual, like an illustration, I’ll often throw on a long podcast or audiobook to keep me focused. With visual work, I’m using a different part of my brain that involves a lot less verbal processing, so in the silence, my own internal dialog starts to take over. And I have a &lt;em&gt;lot&lt;/em&gt; of internal dialogue. Listening to someone tell a story helps keep that in check and prevents my overactive mind from wandering all across the internet.&lt;/p&gt;
&lt;p&gt;If you’re interested in a couple of slightly science-y deeper dives into how our minds work with what we listen to, I recommend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.inc.com/tom-popomaronis/do-you-listen-to-music-while-working-heres-what-it-does-to-your-brain-and-its-pr.html&quot;&gt;&lt;em&gt;What Listening to Music at Work Does to Your Brain (It&apos;s Pretty Amazing)&lt;/em&gt;&lt;/a&gt; - Inc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://science.howstuffworks.com/life/inside-the-mind/human-brain/turn-down-radio-when-lost.htm&quot;&gt;Why do we turn down the radio when we’re lost?&lt;/a&gt; - How Stuff Works&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nytimes.com/2016/04/29/science/this-is-your-brain-on-podcasts.html&quot;&gt;This is your Brain on Podcasts&lt;/a&gt; - The New York Times&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-have-you-tried-that-hasnt-been-particularly-helpful&quot;&gt;&lt;a href=&quot;#what-have-you-tried-that-hasnt-been-particularly-helpful&quot; aria-label=&quot;what have you tried that hasnt been particularly helpful permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;em&gt;What have you tried that hasn’t been particularly helpful?&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Eric&lt;/strong&gt;&lt;br&gt;
Instrumentals and music I’ve never heard before is usually not helpful in getting me to focus or be productive. I’m also not very productive in busy coffee shops or hanging around friends, I usually have to put headphones on to be useful in those scenarios.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kate Farrar&lt;/strong&gt;, Designer, Developer&lt;br&gt;
Ambient noise is very distracting for me, but I like to work in coffee shops because it helps me to get out of the house (and into pants).&lt;/p&gt;
&lt;p&gt;I’ve noticed that even if the overhead music playing is pleasant, I am way too distracted by all the people and things going on around me to concentrate. I have to put on headphones and crank up my music so I basically can’t hear anything else and then I’m able to focus. That gives me a good mix of a new environment but also blocks out noise distraction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Amy&lt;/strong&gt;&lt;br&gt;
If I’m working on anything that requires any sort of linguistic processing (reading, writing emails, mentally trudging through a complex problem) I can’t listen to anything with lyrics or people talking. It overloads the language processing areas of my brain and I feel like can’t get anything done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elliott&lt;/strong&gt;&lt;br&gt;
There are also times when I work &lt;em&gt;really&lt;/em&gt; well in silence. The problem is that it needs to be pretty much absolutely silent. Unfortunately there’s been construction near my house lately which forces me to have some audio going.&lt;/p&gt;
&lt;p&gt;If I’m working out of a coffee shop I need to have my over-ear headphones on. Earbuds just don’t cut out enough background noise for me to focus. If I’m at home I’m pretty much always playing out of a nice pair of speakers I have on my desk.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lynn&lt;/strong&gt;&lt;br&gt;
I’ve tried those “calming” playlists when I’m feeling stressed about something, but it seems to have the opposite effect. They make me want to sleep and then I get more stressed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Amy&lt;/strong&gt;&lt;br&gt;
I strongly avoid anything that I suspect might make feel sad or depressed, I know that those moods are not a productive headspace for me.&lt;/p&gt;
&lt;p&gt;Also YouTube. Therein lies the “Up Next” suggested-video-rabbit-hole that —no matter the original video’s topic— always ends with me tearing up to videos of Ellen Degeneres giving people giant checks to follow their dreams. So touching, but &lt;em&gt;not&lt;/em&gt; productive.&lt;/p&gt;
&lt;h3 id=&quot;what-music-recommendations-do-you-have-for-getting-into-the-zone&quot;&gt;&lt;a href=&quot;#what-music-recommendations-do-you-have-for-getting-into-the-zone&quot; aria-label=&quot;what music recommendations do you have for getting into the zone permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;em&gt;What music recommendations do you have for getting “into the zone”?&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Elliott&lt;/strong&gt;&lt;br&gt;
I’ve become really in to the non-stop “live” YouTube techno &lt;a href=&quot;https://www.youtube.com/watch?v=kA0VEiyF_EM&quot;&gt;channels&lt;/a&gt; because there aren’t words, it’s pretty much always four-on-the-floor, there’s no break, and I like techno. My go-to techno artists for productivity are &lt;a href=&quot;https://www.youtube.com/watch?v=yEbrvMljMCg&quot;&gt;Deborah de Luca&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=U5PtE6rx2Po&quot;&gt;Boris Brejcha&lt;/a&gt;, while my go-to rap artists are &lt;a href=&quot;https://open.spotify.com/artist/2xvtxDNInKDV4AvGmjw6d1?si=hw4TjLPQRcKGCVSFt9wjOg&quot;&gt;Bladee&lt;/a&gt; and &lt;a href=&quot;https://open.spotify.com/artist/7rkW85dBwwrJtlHRDkJDAC?si=W_7pRFY2RcCRpqwg9uqXIA&quot;&gt;Nav&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kate&lt;/strong&gt;&lt;br&gt;
These a few of my favorite playlists / albums when I need to go “heads down”:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://open.spotify.com/user/spotify/playlist/37i9dQZF1DWZeKCadgRdKQ?si=fuw6_yxrS_G7r3dih7wn0Q&quot;&gt;Deep Focus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://open.spotify.com/album/3bcKwRV0LVOmAZzgdxs3xi?si=ZN1uCmrbSqW7587FxmYHFw&quot;&gt;Lebanon PA Soundtrack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://open.spotify.com/album/02gOHdj3c67CUwXb4s9jzy?si=GBux3D8wQ6O697Z1OBn8lw&quot;&gt;Many Beautiful Things Soundtrack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Film scores are some of my favorites because there is usually a good amount of diversity in sound.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Amy&lt;/strong&gt;&lt;br&gt;
When I need to be in a place of hyper focus, I look for something with a lot of raw power to it, like classic rock. &lt;a href=&quot;https://open.spotify.com/album/6mUdeDZCsExyJLMdAfDuwh?si=sTP9Bjk8QYCqoVoekKrCnA&quot;&gt;ACDC’s &lt;em&gt;Back in Black&lt;/em&gt;&lt;/a&gt; is one of my all time productivity favorites. It will make you feel like a bad ass who can handle anything. I also really find a lot of electronic music great for focus. I either gravitate to something a little big and moody like &lt;a href=&quot;https://open.spotify.com/album/0dLnnm4PjeyqM4CoHqo6DI?si=qkCCbDBeRCGP6mCDAgQ-7w&quot;&gt;Justice&lt;/a&gt; or something chill and steady like &lt;a href=&quot;https://open.spotify.com/album/0hQOqvZv1nQvPiBjzyn363?si=RjB22VcaQ4y6ZVxX-wmExQ&quot;&gt;Air&lt;/a&gt; or &lt;a href=&quot;https://open.spotify.com/album/21dbYScNUKn2Y1Vae8lACJ?si=JpKP5grHQLOd30sN1WVXBw&quot;&gt;Tycho&lt;/a&gt;. If you really want to chill out and listen to something that’s prettier than white noise, but equally soothing, I highly recommend &lt;a href=&quot;https://open.spotify.com/album/136AocmGvmUjqNsvAhtfU5?si=1wyF2JIHRyOuIw-y6PmOmg&quot;&gt;Moby’s &lt;em&gt;Long Ambients1: Calm. Sleep.&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally, sometimes, in order to be productive, you just need a break. In times that require something a little goofy to break up the tension, I usually go pure 80’s guilty pleasure and dance with my dog to &lt;a href=&quot;https://open.spotify.com/album/43lok9zd7BW5CoYkXZs7S0?si=PZPjfxBYQ1mKtk9_Djah6g&quot;&gt;early Madonna&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lynn&lt;/strong&gt;&lt;br&gt;
Maybe a bit weird, but listening to the rooster whistling song from Disney’s Robin Hood (the animated fox one) helps me get into the zone for sure. There’s a &lt;a href=&quot;https://youtu.be/e1jvGyzcgPA&quot;&gt;ten hour loop of it on YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We’d love to hear your tips and tricks to achieving productivity zen. Reach out on Twitter at &lt;a href=&quot;https://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; and tell us your favorite songs or link us to your favorite playlists for staying focused.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Why give a conference talk? But also, why not.]]></title><description><![CDATA[Earlier this month I was deciding whether I should speak at a developer conference in the fall and found myself waffling between a pros and…]]></description><link>https://blog.andyet.com/2018/04/24/why-give-a-conference-talk-but-also-why-not/</link><guid isPermaLink="false">https://blog.andyet.com/2018/04/24/why-give-a-conference-talk-but-also-why-not/</guid><pubDate>Tue, 24 Apr 2018 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/58f3aa5bc9e93d5b77b8f91cc8d51820/b17f8/lynnandtonic-conf-talk-guide.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 71.52317880794702%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIDAQX/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAAB6GSZLjk1/8QAGhAAAgIDAAAAAAAAAAAAAAAAAQIAERITIf/aAAgBAQABBQIty4rGsTsRTADP/8QAFREBAQAAAAAAAAAAAAAAAAAAERD/2gAIAQMBAT8BCf/EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPwG1r//EABkQAAIDAQAAAAAAAAAAAAAAABAhAAECMf/aAAgBAQAGPwLri0LP/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAERITFBUXH/2gAIAQEAAT8hRg1+jZKWSO5M5Hslq4pbmyNbR//aAAwDAQACAAMAAAAQ8N//xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAIAQMBAT8Qyiv/xAAWEQADAAAAAAAAAAAAAAAAAAAQETH/2gAIAQIBAT8QRB//xAAcEAEAAgMBAQEAAAAAAAAAAAABABEhMUFhUeH/2gAIAQEAAT8QstpvLVv5DSlnXIue9ZfCChRBssvfyoZpkTK9HMI7ivCp/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;@lynnandtonic’s Guide to Conference Talk Prep: 1. Thesis 2. Outline 3. Steam clean foors 4. Watch entire season of Scandal 5. Sob quietly 6. Slides&quot;
        title=&quot;&quot;
        src=&quot;/static/58f3aa5bc9e93d5b77b8f91cc8d51820/3cb18/lynnandtonic-conf-talk-guide.jpg&quot;
        srcset=&quot;/static/58f3aa5bc9e93d5b77b8f91cc8d51820/0a254/lynnandtonic-conf-talk-guide.jpg 151w,
/static/58f3aa5bc9e93d5b77b8f91cc8d51820/c8fe0/lynnandtonic-conf-talk-guide.jpg 303w,
/static/58f3aa5bc9e93d5b77b8f91cc8d51820/3cb18/lynnandtonic-conf-talk-guide.jpg 605w,
/static/58f3aa5bc9e93d5b77b8f91cc8d51820/39048/lynnandtonic-conf-talk-guide.jpg 908w,
/static/58f3aa5bc9e93d5b77b8f91cc8d51820/5ac89/lynnandtonic-conf-talk-guide.jpg 1210w,
/static/58f3aa5bc9e93d5b77b8f91cc8d51820/b17f8/lynnandtonic-conf-talk-guide.jpg 1600w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Earlier this month I was deciding whether I should speak at a developer conference in the fall and found myself waffling between a pros and cons list. Turns out I ❤️ giving conference talks &lt;em&gt;and&lt;/em&gt; I also don’t?&lt;/p&gt;
&lt;p&gt;Every talk I’ve ever given was ultimately worth doing and I feel so, so grateful for each of those opportunities. But let’s be honest; prepping, traveling for, and giving a quality talk takes &lt;em&gt;work&lt;/em&gt;, physically and emotionally.&lt;/p&gt;
&lt;p&gt;This breakdown of benefits and drawbacks helped me think through the “why?” and “why not?” of speaking this time around.&lt;/p&gt;
&lt;h2 id=&quot;truly-great-benefits&quot;&gt;&lt;a href=&quot;#truly-great-benefits&quot; aria-label=&quot;truly great benefits permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Truly great benefits&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Learning&lt;/strong&gt;&lt;br/&gt;
Prepping a talk requires research and double and triple checking facts. Writing a loose script for others to experience helps me better understand and articulate my process and perspectives. Nothing helps me master a topic like teaching it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Personal growth&lt;/strong&gt;&lt;br/&gt;
Getting up on stage is &lt;em&gt;scary&lt;/em&gt;. Public speaking is no joke in the fear department. Every time I do it, it becomes less intimidating and I become more confident.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Visibility&lt;/strong&gt;&lt;br/&gt;
Giving talks helps introduce new people to my work. These are folks who I may never have met or reached in any other way. It’s super cool to see my projects’ traffic spike after a talk or to see my work shared anew on social media.&lt;/p&gt;
&lt;p&gt;And although I’m not looking for a job, it’s helpful when potential employers have seen me speak or are already familiar with my work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Credibility&lt;/strong&gt;&lt;br/&gt;
Whether it should or not, our industry values speaking at conferences. Having talks on my resume or videos/slides to point to increases my credibility with peers, clients, and with future conferences I might want to speak at too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Introvert assist&lt;/strong&gt;&lt;br/&gt;
Chatting with people at large events can cause anxiety for me, especially if I’m attending solo. Being a speaker is like having an invisible wingperson. People will come talk to me about the topic I chose. It alleviates a lot of the pressure of small talk. Plus, if there’s a speaker dinner, that’s also a less stressful setting for conversation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That Feeling&lt;/strong&gt;™&lt;br/&gt;
After I’m done giving a talk, I feel &lt;em&gt;incredible&lt;/em&gt;. It’s a combination of adrenaline, accomplishment, relief, and a whole bunch of other emotions. All the preparation and the stress and the worrying feel completely worth it. I try to hold on to That Feeling™ for as long as I can. It’s the #1 thing that convinces me to do another talk later on.&lt;/p&gt;
&lt;h2 id=&quot;but-of-course-there-are-drawbacks-too&quot;&gt;&lt;a href=&quot;#but-of-course-there-are-drawbacks-too&quot; aria-label=&quot;but of course there are drawbacks too permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But of course there are drawbacks too&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Time&lt;/strong&gt;&lt;br/&gt;
Even for a 30 minute talk, it takes me months of prep. Research, outline, write, slides, practice. Repeat until the minute I’m on stage. The majority of this work is done outside of my day job hours and a lot of conferences don’t pay their non-keynote speakers. So it can be a significant free time commitment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stress&lt;/strong&gt;&lt;br/&gt;
Even if I feel fully prepared, every moment until the talk is completed I’ll feel stressed out. I’ll be thinking about the talk while in the shower, when I’m out with friends, and OMG I should be working on my talk instead of watching this episode of The Office for the 76th time.&lt;/p&gt;
&lt;p&gt;If I have a lot of other emotionally demanding plans, the stress of a talk can be too much. Or it can cancel out the relaxation I hope for during a vacation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Visibility&lt;/strong&gt;&lt;br/&gt;
On the flipside, sometimes greater visibility can be harmful. Being in the spotlight provides opportunity for negative attention, creepers, or harassment.&lt;/p&gt;
&lt;p&gt;Sometimes the last thing I want is for a large group of people to be looking at me or my work and I know that’s not the season for doing conference talks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Introvert kryptonite&lt;/strong&gt;&lt;br/&gt;
Although being a speaker assists in conversation, it also can be super draining. The stresses of traveling, speaking, and full days of lots of people can leave me ready for a 24-hour nap. I sometimes need to skip the closing party when my talk is scheduled for later in the day. Planning some time to recover is a must for me.&lt;/p&gt;
&lt;h2 id=&quot;why-or-why-not&quot;&gt;&lt;a href=&quot;#why-or-why-not&quot; aria-label=&quot;why or why not permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why or why not?&lt;/h2&gt;
&lt;p&gt;After thinking things through &lt;em&gt;a lot&lt;/em&gt;, I ultimately decided to decline the invitation even though it would have provided a free trip to Europe (oof) and would have been, as I was reminded by friends and family, Good For My Career (double oof). With FOMO ever-present, it can seem like a no brainer to say “yes.”&lt;/p&gt;
&lt;p&gt;Sometimes “yes” is absolutely the right answer, and other times “no” is just as right for me. I know I’ll find another opportunity to speak if/when I feel up for it. And if you’re thinking of giving a conference talk, I do hope you find the right event for you. &amp;#x3C;3&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The official title of this post is “Lift off” (in honor of how good NLF’s puns are), but just to be clear, it’s about the fact that npm acquired ^lift and nsp]]></title><description><![CDATA[It’s with fifteen gallons of mixed emotions that we announce that our friends at npm, inc. have acquired ^lift security and the Node…]]></description><link>https://blog.andyet.com/2018/04/10/lift-off/</link><guid isPermaLink="false">https://blog.andyet.com/2018/04/10/lift-off/</guid><pubDate>Tue, 10 Apr 2018 09:51:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s with fifteen gallons of mixed emotions that we announce that &lt;a href=&quot;http://blog.npmjs.org/post/172793182214/npm-acquires-lift-security-and-node-security&quot;&gt;our friends at npm, inc. have acquired ^lift security and the Node Security Platform&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All the feelings:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sadness&lt;/strong&gt; to see some wonderful people move on from &amp;#x26;yet. &lt;strong&gt;Joy&lt;/strong&gt; for them to experience the ability to focus full-time on their passion for empathetically raising the bar for security, with the resources and audiences of one of the most influential companies in the JS ecosystem. &lt;strong&gt;Eager curiosity&lt;/strong&gt; to see what the impact will be, knowing our former teammates’ immense vision and capabilities. &lt;strong&gt;Pride&lt;/strong&gt; for what our team has built together in ^lift and nsp. &lt;strong&gt;Nostalgia&lt;/strong&gt;, thinking of all the great memories. &lt;strong&gt;Gratitude&lt;/strong&gt; for the experience of working with friends we care about and respect.&lt;/p&gt;
&lt;p&gt;We wish Adam Baldwin, Nathan LaFreniere, Jon Lamendola, and npm success.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;&amp;#x26;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Why do work without a practical purpose?]]></title><description><![CDATA[The first website I ever made was a fansite for a local Phoenix band called 17FourEyes. I was obsessed and compiled everything I knew about…]]></description><link>https://blog.andyet.com/2018/01/24/why-do-work-without-a-practical-purpose/</link><guid isPermaLink="false">https://blog.andyet.com/2018/01/24/why-do-work-without-a-practical-purpose/</guid><pubDate>Wed, 24 Jan 2018 14:30:00 GMT</pubDate><content:encoded>&lt;p&gt;The first website I ever made was a fansite for a local Phoenix band called 17FourEyes. I was &lt;em&gt;obsessed&lt;/em&gt; and compiled everything I knew about them, including transcribing the lyrics to their songs from demos and an eventual EP (I found out later I got a lot wrong). Through the site’s forum I connected with another fan where we gushed together and we eventually started hanging out at their shows. It was just so cool and got me hooked on the magic of the web.&lt;/p&gt;
&lt;p&gt;Fifteen years later you could argue that most of my projects are still glorified fansites. Digital love letters to &lt;a href=&quot;https://a.singlediv.com&quot;&gt;CSS&lt;/a&gt;, &lt;a href=&quot;https://airportcod.es&quot;&gt;airports&lt;/a&gt;, &lt;a href=&quot;https://topchefstats.com&quot;&gt;reality cooking competitions&lt;/a&gt;, and my home state of &lt;a href=&quot;https://why.az&quot;&gt;Arizona&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I joke that I pride myself on creating projects that compel people to post on the internet asking “Why do this?” I recognize my work isn’t for everyone. As recently as last week a friend of mine, who no doubt gets &lt;em&gt;me&lt;/em&gt;, said about the popularity of my &lt;a href=&quot;https://airportcod.es&quot;&gt;airportcod.es&lt;/a&gt; project, “I just don’t get it.”&lt;/p&gt;
&lt;p&gt;A lot of people question the practicality of the work or search for a deeper purpose:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Just wondering, is there any legitimate reason for doing this?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“Sure, it’s challenging, but why should anybody care?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“Really nice but I really don&apos;t see the point.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“Nice one, but WHY??”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My CSS drawing project, &lt;a href=&quot;https://a.singlediv.com&quot;&gt;a.singlediv.com&lt;/a&gt;, is usually on the receiving end of the “Why?”, but my &lt;a href=&quot;https://medium.com/andyet/case-study-lynnandtonic-com-2017-refresh-134620dbd12a&quot;&gt;recent portfolio redesign&lt;/a&gt; brought a fresh set of questioning.&lt;/p&gt;
&lt;p&gt;My prepared goto answer is that these projects are just for fun and hey, it’s fun to do things that are weird. While technically true, there’s so much more I’m trying to do.&lt;/p&gt;
&lt;p&gt;So… why then?&lt;/p&gt;
&lt;p&gt;Why do we create art at all? Some artists create solely for themselves as a means of introspection and self expression. I truly love that. However, I’m not one of those artists.&lt;/p&gt;
&lt;p&gt;I begin my process thinking about who will consume my work and how I hope they’ll respond to it. Art does not exist in isolation and it gains meaning from the people who experience it. It cannot be separate from the context in which it was created and the history of work that came before it. Those who view and participate in the work gain (or sometimes lose) something too.&lt;/p&gt;
&lt;h2 id=&quot;seeing&quot;&gt;&lt;a href=&quot;#seeing&quot; aria-label=&quot;seeing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Seeing&lt;/h2&gt;
&lt;p&gt;Have you ever had a friend send you an image and they say “This is incredible!”? You look at it. It has nice lighting I guess? What’s the big deal? “No, no. It’s not a photo. It’s a 12-foot oil painting.” In a small, special moment you aren’t sure if your eyes are playing tricks on you. “Whaaat?”&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;love&lt;/em&gt; that feeling. Where someone’s work makes you question your reality. It begs you to dig deeper into how they did it. You want to, or in the best cases, &lt;em&gt;must&lt;/em&gt; look closer. Imagine creating something that causes a tiny explosion in someone’s brain. When people view my work, I hope they might say “I didn’t know this was possible.”&lt;/p&gt;
&lt;p&gt;Similarly, I love when someone’s work opens your eyes to something that was &lt;em&gt;always there&lt;/em&gt;. A tool used in a new way, a pattern you never noticed, or the story behind a name. In an instant, this everyday thing is suddenly &lt;em&gt;different&lt;/em&gt; and you can’t unsee it. The response I hope for in this case is, “Oh wow. Of course.”&lt;/p&gt;
&lt;p&gt;Being surprised, stretching our imaginations, seeing things differently. Each an intention of the work and something I gain personally from creating it.&lt;/p&gt;
&lt;p&gt;Experiences like this (as a viewer and a creator) are super valuable for me, especially long term. Every day we’re learning things that will be practical &lt;em&gt;someday&lt;/em&gt;. You may not even realize you’re building this complex web of knowledge. We call it “intuition” but a big part of being an experienced designer/developer/whatever is how vast your web is and how effectively you can make connections between the disparate information and apply them to solve real problems.&lt;/p&gt;
&lt;h2 id=&quot;challenging&quot;&gt;&lt;a href=&quot;#challenging&quot; aria-label=&quot;challenging permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Challenging&lt;/h2&gt;
&lt;p&gt;“Well, which is it? Art or design?!” a frustrated Redditor asks, trying to make sense of one of my projects. That question made me so happy. I want people who feel confused about what the work &lt;em&gt;is&lt;/em&gt; to also question why they want to categorize it.&lt;/p&gt;
&lt;p&gt;Designers do this a lot. I wish I had a piece of pizza for every “Design isn’t art” article I’ve seen. Art and design overlap in deep, meaningful ways and drawing a line between them does both a disservice. Also true for technology, where some want to draw the line even deeper. I want my work to blur the edges. I’m always amazed at the kind of magic we can create in the space where disciplines overlap.&lt;/p&gt;
&lt;p&gt;Doing this work on the web specifically asks people to think about medium. I pay close attention when someone critiques art by saying the artist “must have a lot of time on their hands.” Almost always, it’s in response to work that’s made of unconventional material. Detailed portraits on Starbucks cardboard sleeves or styrofoam cups, landscapes constructed with thousands of matchsticks, drawings made with a single div and CSS. Very rarely does anyone say this about photography, oil painting, or stone sculpture.&lt;/p&gt;
&lt;p&gt;What about a medium makes us value the time spent with it? I hope every person who views my CSS illustrations and says, “I can&apos;t help but ask… why not just use SVG?” really does think about why. What would the work &lt;em&gt;be&lt;/em&gt; if it was created in a format that’s obviously better suited? The medium we choose to work in is &lt;em&gt;part of the work&lt;/em&gt; and contributes to its meaning.&lt;/p&gt;
&lt;h2 id=&quot;sharing&quot;&gt;&lt;a href=&quot;#sharing&quot; aria-label=&quot;sharing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sharing&lt;/h2&gt;
&lt;p&gt;Lately the web can feel like an overwhelming sea of misery. (I won’t get into it. You know.) But it’s still such a joy to discover someone who shares in your weird, obsessive love for something. Maybe you stumble upon a website that feels like it was made just for you.&lt;/p&gt;
&lt;p&gt;“Stumbling” upon something is such an important part of the web we take for granted. A huge contributor to a work of art’s meaning is how people access it. Does it exist in a physical space? Must you pay to enter that space and are the hours of access limited? Can people participate in it, contribute to it?&lt;/p&gt;
&lt;p&gt;Connecting through art or shared passion is a gift and the web makes that possible at a scale unlike anything before. My little fansite turned a stranger into a friend, connecting on the web and at rock shows in the Nile basement. And that magic has only grown with every project since.&lt;/p&gt;
&lt;p&gt;The joy we feel about the things we love is worth sharing and I encourage you to do it! You and the people viewing your work can benefit in a lot of ways, even if “the practicality of this is just non-existent.” 😉&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Case Study: lynnandtonic.com 2017 refresh]]></title><description><![CDATA[Over the past ten years I’ve made ten different versions of my website. I call it my annual portfolio “refresh” since the content usually…]]></description><link>https://blog.andyet.com/2018/01/09/case-study-lynnandtonic-refresh/</link><guid isPermaLink="false">https://blog.andyet.com/2018/01/09/case-study-lynnandtonic-refresh/</guid><pubDate>Tue, 09 Jan 2018 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over the past ten years I’ve made ten different versions of my website. I call it my annual portfolio “refresh” since the content usually stays the same. I do always start with a blank CSS file.&lt;/p&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 68.21192052980133%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABAAF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQD/2gAMAwEAAhADEAAAAdM2gETyIv/EABoQAAMBAAMAAAAAAAAAAAAAAAECAwASEyH/2gAIAQEAAQUCM2Gp2glLk+ayBnReI//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAHxAAAgECBwAAAAAAAAAAAAAAAAERAgMSIjFBUYGR/9oACAEBAAY/Asl19iiao43JxP00EQj/xAAcEAACAgIDAAAAAAAAAAAAAAABEQAhQVExYZH/2gAIAQEAAT8hsAD3cO7XLCC9B4aLR5HQ60VBmDTdmf/aAAwDAQACAAMAAAAQ0O//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8Qpsf/xAAWEQEBAQAAAAAAAAAAAAAAAAAAESH/2gAIAQIBAT8Qhr//xAAdEAEAAwABBQAAAAAAAAAAAAABABEhYTFBUbHR/9oACAEBAAE/EDLFxoIb0PPMw+O8NXeUSisBBnEuX0ILEBE+aJItdqqhxP/Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;lynnandtonic.com v2016&quot;
        title=&quot;&quot;
        src=&quot;/static/14b510949addef3920db3b138b62cef7/3cb18/lynnandtonic-version-old.jpg&quot;
        srcset=&quot;/static/14b510949addef3920db3b138b62cef7/0a254/lynnandtonic-version-old.jpg 151w,
/static/14b510949addef3920db3b138b62cef7/c8fe0/lynnandtonic-version-old.jpg 303w,
/static/14b510949addef3920db3b138b62cef7/3cb18/lynnandtonic-version-old.jpg 605w,
/static/14b510949addef3920db3b138b62cef7/39048/lynnandtonic-version-old.jpg 908w,
/static/14b510949addef3920db3b138b62cef7/e5166/lynnandtonic-version-old.jpg 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;small style=&apos;text-align:center;display:block;&apos;&gt;some past iterations of &lt;a href=&apos;https://lynnandtonic.com&apos;&gt;lynnandtonic.com&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;I do this each year for a few reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;to ensure I’ll complete at least one non-work project&lt;/li&gt;
&lt;li&gt;to experiment with and learn new techniques (a few standout refreshes were my first attempts at responsive design, flexbox, and this year, CSS grid)&lt;/li&gt;
&lt;li&gt;a year is about the right amount of time for a version to exist where I don’t feel sad once I sit down to change it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, a truly great thing about redoing my own site is that it’s fully mine and I can do whatever the heck I want. 😊&lt;/p&gt;
&lt;p&gt;A very small percentage of my portfolio’s visitors are &lt;a href=&quot;http://airportcod.es/&quot;&gt;airport enthusiasts&lt;/a&gt;, &lt;a href=&quot;http://topchefstats.com/&quot;&gt;Top Chef viewers&lt;/a&gt;, and family (hi, mom). But the primary audience is overwhelmingly web designers, developers, and tech recruiters. These are people who know how websites are built and might take an extra minute to inspect things. I wanted to design around that.&lt;/p&gt;
&lt;h2 id=&quot;concept-and-inspiration&quot;&gt;&lt;a href=&quot;#concept-and-inspiration&quot; aria-label=&quot;concept and inspiration permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Concept and inspiration&lt;/h2&gt;
&lt;p&gt;For years we’ve been telling the world that a website doesn’t need to look the exact same in every browser for every user. With responsive design and progressive enhancement, users &lt;em&gt;will&lt;/em&gt; see things differently. Not everyone needs to experience the entirety of the site.&lt;/p&gt;
&lt;p&gt;But could I make people &lt;em&gt;want&lt;/em&gt; to experience all of it? Could I surprise them by taking these concepts to an absurd extreme?&lt;/p&gt;
&lt;p&gt;I love to resize my browser and see how the layout responds and how the designer decided when things change and what gets dropped or added. I know lots of other people do this too. I initially thought I could subvert expectations by making the ubiquitous phone, tablet, and desktop breakpoints trigger completely different layouts with unique styles, colors, and type treatments. Three sites in one.&lt;/p&gt;
&lt;p&gt;The changes, as dramatic as they might have been, still felt too conventional. You already expect something to happen at tablet size and then again for phones.&lt;/p&gt;
&lt;p&gt;I’d recently watched a &lt;a href=&quot;https://youtu.be/Vy2Vhnqtu8I&quot;&gt;YouTube video&lt;/a&gt; about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Kuleshov_effect&quot;&gt;Kuleshov Effect&lt;/a&gt;, a term in film editing that describes “a phenomenon by which viewers derive more meaning from the interaction of two sequential shots than from a single shot in isolation.” A metaphorical bell chimed in my head.&lt;/p&gt;
&lt;p&gt;There’s preexisting meaning for a site to have three (or a few more) distinct layouts: supporting common devices. But what would it &lt;em&gt;mean&lt;/em&gt; for there to be 10, 15, or ultimately 21 distinct designs that “sit” side by side for you to discover one at a time, one after the other. Each one may be unremarkable on its own, but it’s the relationships (and differences) with the ones to the left/right and to the 18 others that make each one worth looking at.&lt;/p&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 66.88741721854305%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMFBAb/xAAVAQEBAAAAAAAAAAAAAAAAAAABA//aAAwDAQACEAMQAAABrIzxZvWjCh//xAAaEAEAAwADAAAAAAAAAAAAAAACAAEDBRMz/9oACAEBAAEFAmzBrSumZyXji77Z/8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8Bp//EABcRAQADAAAAAAAAAAAAAAAAAAEDEBH/2gAIAQIBAT8BYxdr/8QAHRAAAQIHAAAAAAAAAAAAAAAAAAEyAgMQETFScv/aAAgBAQAGPwJw6xkh6Ja6rT//xAAaEAEBAQEAAwAAAAAAAAAAAAABEQAhUXHw/9oACAEBAAE/IQi8IWZIPgjknMUn8jhg5A910N//2gAMAwEAAgADAAAAEDfP/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAR/9oACAEDAQE/EBhk/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAEh/9oACAECAQE/EEkx/8QAGxABAAMBAQEBAAAAAAAAAAAAAQARITGhQWH/2gAIAQEAAT8QPISVqsPI0OjZds7zvSYzQy6Y5MCLILuIQPjbxqfgT//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;one layout of lynnandtonic.com v2017&quot;
        title=&quot;&quot;
        src=&quot;/static/78aa85df56011409828f4a554a968481/3cb18/lynnandtonic-version-new.jpg&quot;
        srcset=&quot;/static/78aa85df56011409828f4a554a968481/0a254/lynnandtonic-version-new.jpg 151w,
/static/78aa85df56011409828f4a554a968481/c8fe0/lynnandtonic-version-new.jpg 303w,
/static/78aa85df56011409828f4a554a968481/3cb18/lynnandtonic-version-new.jpg 605w,
/static/78aa85df56011409828f4a554a968481/39048/lynnandtonic-version-new.jpg 908w,
/static/78aa85df56011409828f4a554a968481/e5166/lynnandtonic-version-new.jpg 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
&lt;small style=&apos;text-align:center;display:block;&apos;&gt;A preview of &lt;a href=&apos;https://lynnandtonic.com&apos;&gt;lynnandtonic.com&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;executing-the-idea&quot;&gt;&lt;a href=&quot;#executing-the-idea&quot; aria-label=&quot;executing the idea permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Executing the idea&lt;/h2&gt;
&lt;p&gt;I already knew it was possible to use CSS to turn basic markup into something extraordinary. &lt;a href=&quot;http://www.csszengarden.com/&quot;&gt;CSS Zen Garden&lt;/a&gt; showed us this repeatedly for years. Another side project of mine, &lt;a href=&quot;http://a.singlediv.com&quot;&gt;a.singlediv.com&lt;/a&gt;, takes this concept to ridiculous extremes (I sense a pattern here).&lt;/p&gt;
&lt;p&gt;So executing this redesign started with basic HTML. One thing I’ve learned over the years of experimenting with CSS is you can achieve &lt;em&gt;a lot&lt;/em&gt; without needing to sacrifice clean markup.
Here’s what I landed on. The &lt;code class=&quot;language-text&quot;&gt;&amp;lt;span&amp;gt;&lt;/code&gt;s inside of the &lt;code class=&quot;language-text&quot;&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;&amp;lt;p class=&amp;#39;intro&amp;#39;&amp;gt;&lt;/code&gt; would allow me to style each line differently if I needed and the &lt;code class=&quot;language-text&quot;&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element would allow for a responsive image plus provide additional &lt;code class=&quot;language-text&quot;&gt;:before&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;:after&lt;/code&gt; pseudo-elements (which &lt;code class=&quot;language-text&quot;&gt;&amp;lt;img&amp;gt;&lt;/code&gt; doesn’t allow).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;home&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;nav&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;main-nav&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;nav-home&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;/&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Home&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;nav-web&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;/web&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Web&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;nav-art&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;/art&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Art&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;nav-about&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;/about&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;About&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;nav-thoughts&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;/thoughts&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Thoughts&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;nav&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Lynn Fisher&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;desc&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;artist and designer from Phoenix, Arizona&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;intro&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;I make things for the web and for walls.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;I specialize in light-hearted projects that make people say, “I don’t get it.”&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Yes, I’ve heard of SVG.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;picture&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;lynn&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;/assets/images/lynn-small.png&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;(max-width: 1400px)&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;/assets/images/lynn.png&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;/assets/images/lynn.png&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token attr-name&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;a photo of the artist&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;picture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Also I guess I should add a disclaimer here. I’m the only one touching this code so I set things up the way that worked for me. Of course there are different and surely better ways of doing all of this. 🙂&lt;/p&gt;
&lt;p&gt;I use Stylus for CSS preprocessing (and will in the following examples). I first created a &lt;code class=&quot;language-text&quot;&gt;home.styl&lt;/code&gt; where a reset and variables would be imported, basic page styles would be declared, and where the media queries would be set up. It, plus the other pages, would import into one &lt;code class=&quot;language-text&quot;&gt;main.styl&lt;/code&gt; that gets compiled and minimized. The structure looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;📁 _styl
  📁 components
  📁 globals
  📂 pages
    📄 about.styl
    📄 home.styl
    📄 thoughts.styl
    📄 work.styl
  📄 main.styl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I planned on using CSS grid for this redesign, so I created a super basic fallback layout to show by default (separated into its own file in a &lt;code class=&quot;language-text&quot;&gt;home&lt;/code&gt; directory) and I placed everything else inside a &lt;code class=&quot;language-text&quot;&gt;@supports&lt;/code&gt; declaration.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;📁 _styl
  📂 pages
    📂 home
      📄 fallback.styl
    📄 home.styl
  📄 main.styl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* home.styl */&lt;/span&gt;

@import &lt;span class=&quot;token string&quot;&gt;&apos;home/fallback&apos;&lt;/span&gt;

@supports &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  body.home
    [base styles here]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If a browser doesn’t support &lt;code class=&quot;language-text&quot;&gt;display: grid&lt;/code&gt; it will render the fallback, which looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3f44ff5e67e2c74ea04b8671c5fef15f/e5166/lynnandtonic-version-fallback.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 68.87417218543047%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHelrWGAr//xAAXEAADAQAAAAAAAAAAAAAAAAABAxBB/9oACAEBAAEFAsS0NME//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFxAAAwEAAAAAAAAAAAAAAAAAAAEgYf/aAAgBAQAGPwIeT//EABoQAQABBQAAAAAAAAAAAAAAAAEQABEhMZH/2gAIAQEAAT8hcaUYhxItH//aAAwDAQACAAMAAAAQ9M//xAAXEQEAAwAAAAAAAAAAAAAAAAABEBEh/9oACAEDAQE/EByo/8QAFhEBAQEAAAAAAAAAAAAAAAAAAREQ/9oACAECAQE/EErbn//EABwQAQACAgMBAAAAAAAAAAAAAAEAESExQVFhof/aAAgBAQABPxDMSyF0czSWF6V58Yh0R1iXGgy5jP/Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;fallback for browsers that don&apos;t support CSS grid&quot;
        title=&quot;&quot;
        src=&quot;/static/3f44ff5e67e2c74ea04b8671c5fef15f/3cb18/lynnandtonic-version-fallback.jpg&quot;
        srcset=&quot;/static/3f44ff5e67e2c74ea04b8671c5fef15f/0a254/lynnandtonic-version-fallback.jpg 151w,
/static/3f44ff5e67e2c74ea04b8671c5fef15f/c8fe0/lynnandtonic-version-fallback.jpg 303w,
/static/3f44ff5e67e2c74ea04b8671c5fef15f/3cb18/lynnandtonic-version-fallback.jpg 605w,
/static/3f44ff5e67e2c74ea04b8671c5fef15f/39048/lynnandtonic-version-fallback.jpg 908w,
/static/3f44ff5e67e2c74ea04b8671c5fef15f/e5166/lynnandtonic-version-fallback.jpg 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With a fallback in place, I could now focus on the many different layouts. To keep things manageable, I split up each layout into its own file alongside the &lt;code class=&quot;language-text&quot;&gt;fallback.styl&lt;/code&gt; in the &lt;code class=&quot;language-text&quot;&gt;home&lt;/code&gt; directory (don’t mind my ridiculous naming).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;📁 _styl
  📂 pages
    📂 home
      📄 b-and-w-and-gold-all-over.styl
      📄 big-nav.style
      📄 big.styl
      📄 blockhead.styl
      📄 bolt.style
      📄 cutout.styl
      📄 diagonal.styl
      📄 disguise.styl
      📄 fallback.styl
      📄 fifty-fifty.styl
      📄 half.styl
      📄 L-Y-N-N.styl
      📄 landscape.styl
      📄 movie.styl
      📄 pop-out.styl
      📄 rotate.styl
      📄 stranger.styl
      📄 third.styl
      📄 triangle.styl
      📄 white-bars.styl
      📄 white-box.styl
      📄 x.styl
    📄 home.styl
  📄 main.styl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then I was able to import each layout into its own media query:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;css&quot;&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* home.styl */&lt;/span&gt;

@supports &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; grid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  body.home
    [base styles here]

  @media screen and &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    @import &lt;span class=&quot;token string&quot;&gt;&apos;home/diagonal&apos;&lt;/span&gt;

  @media screen and &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 401px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; and &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 500px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    @import &lt;span class=&quot;token string&quot;&gt;&apos;home/L-Y-N-N&apos;&lt;/span&gt;

  @media screen and &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;min-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 501px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; and &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;max-width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 600px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    @import &lt;span class=&quot;token string&quot;&gt;&apos;home/blockhead&apos;&lt;/span&gt;

  + 18 more &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;2300px being the widest media query&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This removes any collisions that might happen and eliminates the need to do massive overrides. There is some repeated styling across various layouts, but I found that acceptable to keep things clear and organized. Each breakpoint is only using the CSS it needs for its specific layout.&lt;/p&gt;
&lt;h2 id=&quot;further-learning&quot;&gt;&lt;a href=&quot;#further-learning&quot; aria-label=&quot;further learning permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further learning&lt;/h2&gt;
&lt;p&gt;If you’re interested in digging into the CSS a bit more or to inspect individual layouts, I made my repo &lt;a href=&quot;https://github.com/lynnandtonic/lynnandtonic.com&quot;&gt;public on GitHub&lt;/a&gt;. 🙈&lt;/p&gt;
&lt;p&gt;I won’t go into how to use grid here as &lt;a href=&quot;https://twitter.com/rachelandrew&quot;&gt;Rachel Andrew&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/jensimmons&quot;&gt;Jen Simmons&lt;/a&gt; have written and spoken extensively on the topic. See Rachel’s &lt;a href=&quot;https://gridbyexample.com/&quot;&gt;Grid by Example&lt;/a&gt; and Jen’s &lt;a href=&quot;http://labs.jensimmons.com/&quot;&gt;Experimental Layout Lab&lt;/a&gt; as good places to start.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/patrickbrosset&quot;&gt;Patrick Brosset&lt;/a&gt; of Mozilla created a video breaking down the use of grid for one of my site’s layouts which is pretty cool:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/wmhYScbIxYk?rel=0&quot; frameborder=&quot;0&quot; gesture=&quot;media&quot; allow=&quot;encrypted-media&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;br&gt;
&lt;p&gt;I planned on elaborating on some of my favorite parts of the redesign here, but I think I want people to be surprised as they explore. So if you haven’t checked it out yet, please do at &lt;a href=&quot;https://lynnandtonic.com&quot;&gt;lynnandtonic.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;response&quot;&gt;&lt;a href=&quot;#response&quot; aria-label=&quot;response permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Response&lt;/h2&gt;
&lt;p&gt;I always hope my work will inspire people to think about their medium and tools differently and to encourage them to experiment with what’s possible.&lt;/p&gt;
&lt;p&gt;The response has been overwhelming and it’s truly wonderful to see people discovering and enjoying the site. I’m so grateful for everyone’s kind and encouraging words.&lt;/p&gt;
&lt;p&gt;One piece of feedback I received is that a lot of people don’t resize their browsers at all. That’s true! And it’s totally okay. The site is still functional even if you don’t know any of the other layouts exist. Well, to be fair, there is one layout that would make for a super confusing experience (&lt;em&gt;Stranger Things&lt;/em&gt; fans might know which one I’m talking about). But with my audience in mind, I figured risk was low.&lt;/p&gt;
&lt;p&gt;With most of my work, there are people who ask “Why do this?” I have another post in the works that dives into the many reasons, but for now: sometimes it’s fun to do things that are weird.&lt;/p&gt;
&lt;p&gt;Thanks for checking out the site. It means the world.&lt;/p&gt;
&lt;p&gt;Until the next redesign,&lt;br&gt;&amp;#x3C;3 Lynn&lt;/p&gt;</content:encoded></item><item><title><![CDATA[A theory of belonging]]></title><description><![CDATA[I used to feel like I belonged on the Internet. I didn’t feel like I belonged much anyplace else, but here, I knew who I was, and I could…]]></description><link>https://blog.andyet.com/2017/06/13/a-theory-of-belonging/</link><guid isPermaLink="false">https://blog.andyet.com/2017/06/13/a-theory-of-belonging/</guid><pubDate>Tue, 13 Jun 2017 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I used to feel like I belonged on the Internet. I didn’t feel like I belonged much anyplace else, but here, I knew who I was, and I could make any possibility happen with the support and encouragement of the other weird folks who called the Internet home.&lt;/p&gt;
&lt;p&gt;For better or worse, the web feels different now. And it’s not just that everybody’s here. It’s that we’ve allowed a few large entities to dictate how we gather together, and we have not questioned whether the decisions they’ve made for their survival and growth are good for us as people.&lt;/p&gt;
&lt;p&gt;There is certainly value in the big box social media we are part of (the fact that everyone is there being one of them), but these spaces are not feeding us as community is supposed to feed us. In fact, for most of us, they can be extremely toxic.&lt;/p&gt;
&lt;p&gt;As unique as each person on our &amp;#x26;yet team is, every one of them is one of the most passionate, caring people I’ve ever met. But that also means we’re a really sensitive bunch. The way our social networks are designed do more to make us feel isolated and anxious rather than filling us with a deep sense of belonging.&lt;/p&gt;
&lt;p&gt;Even more concerning for us, we have so many friends who do not even feel a baseline of safety on the Internet—people from marginalized groups who are deeply impacted by the scale and de-humanization our social networks perpetuate.&lt;/p&gt;
&lt;p&gt;We do not have to live unquestioningly in these systems. In fact, as people in tech, we have a deep responsibility to consider the impact of the tools we build. As people who use these tools, we have a responsibility to consider the way we use them and how it affects us and those around us.&lt;/p&gt;
&lt;p&gt;I want to explore a set of building blocks for creating and engaging in more intentional community online. Some of these are building on concepts that others have explored; others are based on things we’ve learned as builders and caretakers of community.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://gallery.mailchimp.com/faa323952110d5be6830f05f5/images/3f29a181-1fe9-46c5-8088-ff80310d2424.png&quot; alt=&quot;Big-box social media v. intentional community&quot;&gt;&lt;/p&gt;
&lt;p&gt;We’re taking these building blocks and using them to prototype &lt;a href=&quot;https://andyet.com/community/&quot;&gt;a new kind of compassionate community on the web&lt;/a&gt;. (There are a few spots currently open right now; after that we’ll be closing it so we can focus on onboarding the first set of folks and integrating their feedback in the experience.)&lt;/p&gt;
&lt;p&gt;These concepts are not exhaustive, by any means; I’m curious if there’s something I’ve missed? If so, shoot me an email at &lt;a href=&quot;mailto:sarah@andyet.com&quot;&gt;sarah@andyet.com&lt;/a&gt;. And if you’d like to &lt;a href=&quot;http://andyet.com/community&quot;&gt;join us&lt;/a&gt; as we actually build a community like this, this is your last week to be part of the first group of people doing that.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://andyet.com/community&quot;&gt;We’d love to have you.&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing the &yet Community]]></title><description><![CDATA[June 2nd and 9th sold out; register for the June 16th adventure!The Internet has created the world’s most unsafe and heartless communities…]]></description><link>https://blog.andyet.com/2017/06/06/andyet-community/</link><guid isPermaLink="false">https://blog.andyet.com/2017/06/06/andyet-community/</guid><pubDate>Tue, 06 Jun 2017 08:57:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;June 2nd and 9th sold out; &lt;a href=&quot;http://andyet.com/community&quot;&gt;register for the June 16th adventure&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Internet has created the world’s most unsafe and heartless communities in the same place we’re building our society’s future.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Our most sensitive people, our most marginalized people—the people we need to lead us into a more empathetic future—are being crushed into the ground.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is this the future we want to create?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the words of Tina Turner, we don’t need another hero. We need entire armies of leaders. We believe tiny leaders build on tiny leaders to create tiny powerful fearless societies.&lt;/p&gt;
&lt;p&gt;What will the future we create look like?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://gallery.mailchimp.com/faa323952110d5be6830f05f5/images/18198b3b-2e91-442c-a567-ae4a9e8be9f7.png&quot; alt=&quot;We decide.&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-were-building&quot;&gt;&lt;a href=&quot;#what-were-building&quot; aria-label=&quot;what were building permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What we’re building:&lt;/h2&gt;
&lt;p&gt;&amp;#x26;yet is a community of possibility for compassionate people. We’re bringing together our favorite people on the Internet to create an intentional, ongoing online community.&lt;/p&gt;
&lt;h2 id=&quot;what-to-expect&quot;&gt;&lt;a href=&quot;#what-to-expect&quot; aria-label=&quot;what to expect permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What to expect:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One month onboarding adventure&lt;/strong&gt;: Because we want to be intentional about how we build our community&apos;s culture, this adventure is the first step. You can think of it as a fun and interactive onboarding experience that uses original story, music, film, and illustration to help us learn about ourselves, each other, and how to be in community together.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ongoing community&lt;/strong&gt;: After you&apos;ve completed this expedition, you&apos;ll be invited to the actual community where we&apos;ll all be hanging out. The only way into the community is through the adventure! :)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ongoing surprises&lt;/strong&gt;: We’re collaborating with artists and interesting people (and each other!) to make fun things happen.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-time-commitment&quot;&gt;&lt;a href=&quot;#the-time-commitment&quot; aria-label=&quot;the time commitment permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The time commitment:&lt;/h2&gt;
&lt;p&gt;The onboarding adventure is 4-6 hours of reading, listening, art, and activities. This is spread out over about a month. The ongoing community has optional interactive things that invite your participation for a couple hours a month.&lt;/p&gt;
&lt;h2 id=&quot;the-code-of-conduct&quot;&gt;&lt;a href=&quot;#the-code-of-conduct&quot; aria-label=&quot;the code of conduct permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The code of conduct:&lt;/h2&gt;
&lt;p&gt;Joining means you agree to uphold our community’s &lt;a href=&quot;https://andyet.com/community-code-of-conduct/&quot;&gt;code of conduct&lt;/a&gt;, so we can provide a safe, inclusive, and harassment-free experience for everyone. &lt;/p&gt;
&lt;h2 id=&quot;joining-at-a-later-date&quot;&gt;&lt;a href=&quot;#joining-at-a-later-date&quot; aria-label=&quot;joining at a later date permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Joining at a later date:&lt;/h2&gt;
&lt;p&gt;If the June 16th onboarding adventure doesn’t work for you, keep a lookout; we’ll have more in the future. (It might be a little while though.)&lt;/p&gt;
&lt;h2 id=&quot;cost-and-cancellation&quot;&gt;&lt;a href=&quot;#cost-and-cancellation&quot; aria-label=&quot;cost and cancellation permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Cost and cancellation:&lt;/h2&gt;
&lt;p&gt;The cost is $39/month, which covers our costs to pay all the great folks who’ve worked and are working to make this a wonderful experience for everyone. You can cancel any time.&lt;/p&gt;
&lt;h2 id=&quot;yet-community-scholarship&quot;&gt;&lt;a href=&quot;#yet-community-scholarship&quot; aria-label=&quot;yet community scholarship permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&amp;#x26;yet Community Scholarship&lt;/h2&gt;
&lt;p&gt;Anyone from an underrepresented group in need of financial assistance is invited to apply for our &lt;a href=&quot;https://andyet.com/community-scholarship/&quot;&gt;community scholarship&lt;/a&gt;. (This includes, but is not limited to: women, people of color, LGBTQIA+ people, disabled people, and people facing economic or social hardships.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This community will not be the same without you.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And we mean that in a very real sense. We strongly believe every new person should shape the community in some way, and we want you to be a part of it with us.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://andyet.com/community&quot;&gt;Will you join us&lt;/a&gt;?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Paginating your hapi api]]></title><description><![CDATA[Most APIs will eventually run up against the problem of paginating data.  Sending entire data sets in one request is simply too expensive…]]></description><link>https://blog.andyet.com/2017/02/10/hapi-pagination/</link><guid isPermaLink="false">https://blog.andyet.com/2017/02/10/hapi-pagination/</guid><pubDate>Fri, 10 Feb 2017 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Most APIs will eventually run up against the problem of paginating data.  Sending entire data sets in one request is simply too expensive for both client and server.  I am going to show you an easy way to paginate your data in hapi, in a way that is easy to use in your client code.&lt;/p&gt;
&lt;h3 id=&quot;hapi-pagination&quot;&gt;&lt;a href=&quot;#hapi-pagination&quot; aria-label=&quot;hapi pagination permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;hapi-pagination&lt;/h3&gt;
&lt;p&gt;To add pagination to your API, the first step is to install the &lt;a href=&quot;https://www.npmjs.com/package/hapi-pagination&quot;&gt;hapi-pagination&lt;/a&gt; module.  It will automatically add &lt;code class=&quot;language-text&quot;&gt;page&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;limit&lt;/code&gt; parameters to the routes you want paginated, and is very customizable to suit your particular needs.&lt;/p&gt;
&lt;p&gt;Here&apos;s the config I ended up going with&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;meta&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;location&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;routes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;include&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/cats&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I set the location to &lt;code class=&quot;language-text&quot;&gt;header&lt;/code&gt; because this is the easiest way to add pagination to an existing API.  If you were starting from scratch you could also design it to return pagination data as part of the response body.  The &lt;code class=&quot;language-text&quot;&gt;header&lt;/code&gt; option will return links to the paginated data in the &lt;code class=&quot;language-text&quot;&gt;Link&lt;/code&gt; header, which I will explain in a moment.&lt;/p&gt;
&lt;h3 id=&quot;route-setup&quot;&gt;&lt;a href=&quot;#route-setup&quot; aria-label=&quot;route setup permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;route setup&lt;/h3&gt;
&lt;p&gt;Examples here will be using &lt;a href=&quot;https://www.npmjs.com/package/muckraker&quot;&gt;muckraker&lt;/a&gt; to query the database.  It uses sql with parameter substitutions, and I think it should be easy enough to translate over to whatever you&apos;re using for database queries.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; server &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Hapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Server&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hapi&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Muckraker &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;muckraker&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Muckraker&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* put your db config here*/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//Allows route handlers to access the database through this.db&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&apos;s start with a basic route that returns the contents of a database table&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; method&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/cats&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  description&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Pagination example&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  plugins&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    pagination&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      enabled&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  validate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    query&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      limit&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//Set a sensible default and max page size&lt;/span&gt;
      page&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Joi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;positive&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//Make sure they can&apos;t give a page number that would create a negative offset&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; params &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;page &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;limit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cats&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cat_count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

      request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;totalCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cat_count&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cats&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here are the sql files for the two database queries:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;--cats_one_count.sql&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;::&lt;span class=&quot;token keyword&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; count &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; cats&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;--cats_all.sql&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; cats &lt;span class=&quot;token keyword&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;by&lt;/span&gt; name &lt;span class=&quot;token keyword&quot;&gt;limit&lt;/span&gt; ${&lt;span class=&quot;token keyword&quot;&gt;limit&lt;/span&gt;} &lt;span class=&quot;token keyword&quot;&gt;offset&lt;/span&gt; ${&lt;span class=&quot;token keyword&quot;&gt;offset&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Don&apos;t forget to order before you limit and offset or you&apos;ll get unpredictable results!&lt;/p&gt;
&lt;p&gt;You could pass in more parameters to both queries if you wanted. Muckraker ignores extra parameters so you can send the same &lt;code class=&quot;language-text&quot;&gt;params&lt;/code&gt; to both queries. I like doing it that way because it lessens the likelihood I&apos;m sending different where clauses to either query.&lt;/p&gt;
&lt;p&gt;This is all you need to do at the most basic level to add pagination to your route.&lt;/p&gt;
&lt;h3 id=&quot;client-setup&quot;&gt;&lt;a href=&quot;#client-setup&quot; aria-label=&quot;client setup permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;client setup&lt;/h3&gt;
&lt;p&gt;The next step is adding pagination awareness to your client.  What we will be doing is parsing the &lt;code class=&quot;language-text&quot;&gt;Link&lt;/code&gt; header and acting accordingly.  There are a LOT of client side code patterns out there.  I am going to try to keep the examples here a little bit abstract because I don&apos;t want to get bogged down in domain-specific approaches.&lt;/p&gt;
&lt;p&gt;First, we need to parse the &lt;code class=&quot;language-text&quot;&gt;Link&lt;/code&gt; header when we parse the response from the server.  I am using the approach that the node &lt;a href=&quot;https://npmjs.com/package/github&quot;&gt;github&lt;/a&gt; library uses &lt;a href=&quot;https://github.com/mikedeboer/node-github/blob/7f7e14b4fc3e64110bb7b9b069674ef804f4a0f6/index.js#L414&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Add this somewhere in the code that parses the response from the API:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; link &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//Link header from the response, may look different in your framework&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; links &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  link&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;/&amp;lt;([^&gt;]*)&gt;;\s*rel=&quot;([\w]*)\&quot;/g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;m&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; uri&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    links&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; uri&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;links &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; links&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//Set a links attribute on this collection, may look different in your framework&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The idea is that now you have a &lt;code class=&quot;language-text&quot;&gt;links&lt;/code&gt; attribute you can check to see if there is more data to get from the server.  If there is a next page then &lt;code class=&quot;language-text&quot;&gt;this.links.next&lt;/code&gt; will exist, and if there is a previous page &lt;code class=&quot;language-text&quot;&gt;this.links.prev&lt;/code&gt; will exist.  You can use these attributes to determine whether or not to display &lt;code class=&quot;language-text&quot;&gt;next&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;prev&lt;/code&gt; navigation options to the user, or simply to query them to fetch all the data to the client at once.&lt;/p&gt;
&lt;p&gt;For now let&apos;s go forward as if we wanted to pass the pagination on to the end user.  I like to decorate my collections with a few methods for pagination like this.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;next&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;next&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reset&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//Backbone style fetch, may look different in your framework&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token function-variable function&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;links&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prev&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reset&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;//Backbone style fetch, may look different in your framework&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What&apos;s going on here is that we&apos;re checking the &lt;code class=&quot;language-text&quot;&gt;links&lt;/code&gt; object we built when we parsed the response from the server, and using it to fetch the next or previous page of data.  You could also conditionally show pagination buttons based on the presence of &lt;code class=&quot;language-text&quot;&gt;this.links.next&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;this.links.prev&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;There is a lot more you could do with this, but we already have a very basic end-to-end pagination approach for both API and client.&lt;/p&gt;
&lt;h3 id=&quot;further-reading&quot;&gt;&lt;a href=&quot;#further-reading&quot; aria-label=&quot;further reading permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further reading&lt;/h3&gt;
&lt;p&gt;I&apos;m currently using this approach for my personal hobby site. I have made the source code available for both the &lt;a href=&quot;https://github.com/wraithgar/api.lift.zone&quot;&gt;api&lt;/a&gt; and &lt;a href=&quot;https://wraithgar/lift.zone&quot;&gt;client&lt;/a&gt;.  If you&apos;d like to say hi, you can find me on Twitter &lt;a href=&quot;https://twitter.com/wraithgar&quot;&gt;@wraithgar&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[People first]]></title><description><![CDATA[A rare re-post of our latest &you newsletterAmerica First?This newsletter’s theme was supposed to be finding your place, inspired by Sarah’s…]]></description><link>https://blog.andyet.com/2017/02/02/people-first/</link><guid isPermaLink="false">https://blog.andyet.com/2017/02/02/people-first/</guid><pubDate>Thu, 02 Feb 2017 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;A rare re-post of our latest &lt;a href=&quot;https://andyet.com/andyou&quot;&gt;&amp;#x26;you newsletter&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://gallery.mailchimp.com/faa323952110d5be6830f05f5/images/5b88af7a-ca48-47e4-9ad9-2e5a90dad962.png&quot; alt=&quot;America First?&quot;&gt;&lt;/p&gt;
&lt;p&gt;This newsletter’s theme was supposed to be finding your place, inspired by Sarah’s move across the country. We likely would have shared something about the definition of “the good life” given by one of our heroes, Cheryl Broetje: &lt;em&gt;&lt;a href=&quot;https://vimeo.com/50174028&quot;&gt;living in the place you belong, with the people you love, doing the work that’s yours—on purpose.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But our team felt it would be extremely poor taste to talk about finding your place when our president has taken actions which fly in the face of our nation’s most foundational ideals, well described by the poem on the Statue of Liberty:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Give me your tired, your poor,&lt;/em&gt;
&lt;em&gt;Your huddled masses yearning to breathe free,&lt;/em&gt;
&lt;em&gt;The wretched refuse of your teeming shore.&lt;/em&gt;
&lt;em&gt;Send these, the homeless, tempest-tost to me,&lt;/em&gt;
&lt;em&gt;I lift my lamp beside the golden door!”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When it comes to political discussions, the advice to businesses sounds like the words of Hamilton’s fictionalized Aaron Burr: &lt;em&gt;“Talk less. Smile more. Don’t let them know what you’re against or what you’re for.”&lt;/em&gt; I made a commitment after the election to being a better person and a better citizen and to making &amp;#x26;yet a better company. I am spending this year seeking the answer to the question: “Who will &amp;#x26;yet be for the next 10 years?” One thing I know I do not want us to be is silent.&lt;/p&gt;
&lt;p&gt;It’s been a hard week for anyone who believes in who the USA &lt;em&gt;can&lt;/em&gt; be based on the bold, aspirational vision of a land where all people are equal, where immigrants are welcomed with open arms, where no one religion rules the land, where the government serves and answers to the people—a vision we’ve still not lived up to, but which we’ve seen take two steps forward and one step back for two-plus centuries.&lt;/p&gt;
&lt;p&gt;The slogan for the current presidential administration is “America First.” It sure sounds patriotic, but many feared what it might mean on a policy level: xenophobia and anti-immigration, putting profit ahead of people, instructing the world to be submissive to our power and to bear the consequences of our endless appetite. It’s not about the aspirational ideals and values of America at all. “America First” might be more accurately described as “me first.”&lt;/p&gt;
&lt;p&gt;Just a few days into this presidency, this fear hasn’t proven unfounded. I have found myself so disturbed and emotionally raw by the state of our nation, I disabled all my social media accounts. Being inundated with an overwhelming flood of terrible news was making me feel ashamed, overwhelmed, and powerless. I needed to recover and focus on what I &lt;em&gt;could&lt;/em&gt; do.&lt;/p&gt;
&lt;p&gt;The most recent moves by this administration regarding immigrants and refugees have been so hard to stomach. I am overwhelmed with grief when I look at our world’s refugee crisis through the photographer’s lens. It doesn’t take more than a couple photos to feel a sense of the desperation and hopelessness that’s well-expressed by the Somali poet Warsan Shire: &lt;a href=&quot;http://seekershub.org/blog/2015/09/home-warsan-shire/&quot;&gt;“No one leaves home unless home is the mouth of a shark.”&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In 1977, the &lt;em&gt;Voyager&lt;/em&gt; spacecraft set out to travel deep into space. Today, it has passed the edge of our solar system. The message it contains is a powerful one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This Voyager spacecraft was constructed by the United States of America. We are a community of 240 million human beings among the more than 4 billion who inhabit the planet Earth. We human beings are still divided into nation states, but these states are rapidly becoming a single global civilization.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;We cast this message into the cosmos. It is likely to survive a billion years into our future, when our civilization is profoundly altered and the surface of the Earth may be vastly changed. Of the 200 billion stars in the Milky Way galaxy, some--perhaps many--may have inhabited planets and spacefaring civilizations. If one such civilization intercepts Voyager and can understand these recorded contents, here is our message:&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This is a present from a small distant world, a token of our sounds, our science, our images, our music, our thoughts, and our feelings. We are attempting to survive our time so we may live into yours. We hope someday, having solved the problems we face, to join a community of galactic civilizations. This record represents our hope and our determination, and our good will in a vast and awesome universe.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Forty years later, it feels like we are moving in the opposite direction of this vision. Yet there is reason for hope.&lt;/p&gt;
&lt;p&gt;We live in a nation that holds some very idealistic values. We have never fully lived out those values and we have certainly never been perfect—far from it, in fact. We displaced a massive native population. We were founded by people who owned people. We’ve been led by people who slaughtered natives and created our own refugee crisis. We unjustly imprisoned people for their race. We’ve fought wars over wealth and resources and “our (comfortable) way of life.” But no matter what we’ve done, our commitment to our ideals has drawn us forward.&lt;/p&gt;
&lt;p&gt;This past December, Amy made our team new hoodies. Our old ones have an ampersand on the breast and say “&amp;#x26;yetis” on the back. We were trying to determine what to put on the back but ultimately went with our core value: “People first.”&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cldup.com/yvwaeb1oiW.png&quot; alt=&quot;People First&quot;&gt;&lt;/p&gt;
&lt;p&gt;For us, this phrase usually is a statement about the importance of individual people being more valuable than ideas or profit or plans.&lt;/p&gt;
&lt;p&gt;But since the inauguration, every time I have put on this sweatshirt, I have done so as a protest against the broken mentality of “America First.” I think we can do better than a small-minded, selfish view of the world that prioritizes one kind of people over another.&lt;/p&gt;
&lt;p&gt;It’s so easy to point fingers and assign blame in politics. Laying it all at the feet of our new president is a cop-out. I’m complicit, too. Our consumeristic view of politics means that we get to abdicate responsibility when someone is in power who we feel matches our worldview.&lt;/p&gt;
&lt;p&gt;The 10,000 refugees the Obama administration said they were going to let in is nearly as shameful, in some ways. We kept the crack of hope open wide enough to say we weren’t completely abandoning our values. It upset me deeply that we weren’t doing more, and I expressed that, but I’m embarrassed to say I moved on.&lt;/p&gt;
&lt;p&gt;When it comes to the Syrian refugee crisis, it’s been comfortable to let someone else drive, feeling like the US was going to head in the right direction while we sat by. We were wrong. Doing that is a big part of what got us to today. But, as our colleague Gar once said, “The best thing about being wrong is you get to be right again.”&lt;/p&gt;
&lt;p&gt;We each look at photos of refugees and ache. The world &lt;em&gt;should&lt;/em&gt; be better. Like you, we believe it’s possible. But probably &lt;em&gt;also&lt;/em&gt; like you, we have found it so easy to feel powerless these days.&lt;/p&gt;
&lt;p&gt;And yet we are not powerless—not by a long shot.&lt;/p&gt;
&lt;p&gt;No one can stop us from making things better than they are right now. And resigning ourselves to powerlessness undermines the most fundamental truth that our government serves the people.&lt;/p&gt;
&lt;p&gt;The current administration has given us a wake-up call to how fully we’ve abdicated our power as citizens. The new president said in his inauguration speech his goal was to restore power to the American people. Ironically, he may be correct in that as the ultimate outcome.&lt;/p&gt;
&lt;p&gt;Years ago, I heard &lt;a href=&quot;http://twitter.com/substack&quot;&gt;Substack&lt;/a&gt; say something that hit me deeply. He was describing the tiny modules philosophy that is a core tenet of Node architecture and said: “Tiny modules build on other tiny modules to make tiny powerful high level abstractions.” I realized the same applies to people—and that this same sentiment summed up what I believe about leadership, collaboration, and communities:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tiny leaders build on other tiny leaders to create tiny resilient fearless societies.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our world needs tiny people like us, tiny companies like ours, and the people we are surrounded by to add our voices and our hands to leading our society. We need leaders who constantly make room for more leaders—not fewer. We need you.&lt;/p&gt;
&lt;p&gt;In the immortal words of Tina Turner, “we don’t need another hero.” No, our world needs entire armies of leaders. And we need to believe that’s not just enough—it’s the most powerful force on earth.&lt;/p&gt;
&lt;p&gt;Aziz Ansari &lt;a href=&quot;https://www.youtube.com/watch?v=Whde50AacZs&quot;&gt;nailed it&lt;/a&gt;: “If you look at our country’s history, change doesn’t come from presidents. Change comes from large groups of angry people—and if day one is any indication, you are part of the largest group of angry people I have ever seen.”&lt;/p&gt;
&lt;p&gt;It’s so easy to feel cowed by the sheer force of power, but &lt;a href=&quot;https://twitter.com/jennwrites&quot;&gt;Jenn&lt;/a&gt; pointed to &lt;a href=&quot;https://twitter.com/blowticious/status/826582040472645633&quot;&gt;this thread&lt;/a&gt; illustrating the many ways engaged people have already had an impact.&lt;/p&gt;
&lt;p&gt;David Foster Wallace said that real leaders are people who “help us overcome the limitations of our own individual laziness and selfishness and weakness and fear and get us to do better, harder things than we can get ourselves to do on our own.”&lt;/p&gt;
&lt;p&gt;We need to do exactly that—for each other.&lt;/p&gt;
&lt;p&gt;We need to encourage people that it &lt;em&gt;matters&lt;/em&gt; that they stand. We need to stand with each other, stand up for each other, stand beside each other. We need each other’s help to believe our voice, our phone calls, and our small, repeated actions matter. We need to ask for each other’s help to remember to rest and take care of ourselves and our mental health, to save our strength for a long marathon.&lt;/p&gt;
&lt;p&gt;The world &lt;em&gt;should&lt;/em&gt; be better. Like you, we believe it’s possible—together.&lt;/p&gt;
&lt;p&gt;So here’s to &lt;em&gt;you&lt;/em&gt;—wherever you are and however you’re fighting for truth, justice, and the &lt;em&gt;real&lt;/em&gt; American way: not “America First,” not “&lt;em&gt;me&lt;/em&gt; first,” but “&lt;em&gt;People&lt;/em&gt; first.”&lt;/p&gt;
&lt;p&gt;We’re with you!&lt;/p&gt;
&lt;p&gt;&amp;#x3C;3&lt;/p&gt;
&lt;p&gt;&amp;#x26;yet&lt;/p&gt;
&lt;p&gt;P.S. We might have to order some more hoodies. ;) In fact—we are!&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&quot;https://store.andyet.com/&quot;&gt;pre-order a super-soft “People first” hoodie here&lt;/a&gt; for $48 + shipping. We’re donating 100% of the profits to the ACLU—at least $15 from each hoodie).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cldup.com/JHdp0B903N-1200x1200.jpeg&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[WTF is &yet story mode?]]></title><description><![CDATA[We’ve been getting a lot of questions about the weird thing we’re doing on our home page. Most of them are some version of WTF? So I thought…]]></description><link>https://blog.andyet.com/2016/12/07/wtf-is-andyet-story-mode/</link><guid isPermaLink="false">https://blog.andyet.com/2016/12/07/wtf-is-andyet-story-mode/</guid><pubDate>Wed, 07 Dec 2016 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7d1525e2a8f0510eded4f485e0d129ab/0a47e/andyet-story-mode.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 600px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 66.88741721854305%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsSAAALEgHS3X78AAADr0lEQVQ4y2NgAIJvzdMZvrfMYEAGP1esYvj35wLD33fHGP4+PcTwa+8Ghm/lkxi+t80EqwXpgYGvuX0IjciGfW8FK2T+3j6T7cf8SQz4ALKhYHbTdIQE1GAmIOYHukDmW+M0ke8ts9j+3D3I8ffjMc4/zw/z/tywWvBb7RSu7x0z2b81TkcxGAMADQBJsH8HGvi1eILk957Zkr+PbZH78/CQ8t/7B9V+XN+t+233BqNvddOUv7bOUPrcMkMEaLkQUA8L2FCgS6/N3MjQeP4TxAagq1i+1U/l/T5pntjPTWt0fx3cZPLr/E6HP7d3uv++vsP+/7Mjlv9fHPL/dWCd9f/8fsn/bdOFvrXOEP/cPIMLZOC2NScYNq8/w1B37hPEq9/bZnAAvSHwo2uW6J/Lu2z/3dnn9P/Udos/93ZF/n+9M/v0liVVh1Yvqv1xf1fy412rAq42ztb/1jBd8P/0+SzYApcVaCjn15YZvH8ap/KczJ4stj1rqtLp9Anyn8/v9Pj/6VTMrOauVXUp1Ut+PDqQfv3I+u719dOCdgR0qH2ctYS94t5/nt4Hv1kmnnvL0LbvCdiFrM9rpnGfyJrMvSlhouDKqH7FtbETdBb4dBmcmLbE5f/bc1H95S2rMv2yj66ZOLXy3IaluataJ/lNrF7nPXnCPs/qNbf0yjbcEym58pOl/NYfBoYPDdNZn1VPE7hcOEX6dM5k9cMZkwz3p08y3xA3wX5lzATXCxNX+s4r7M4pjMjat2ni7MyNUxYnb1u1tmjW/EOFExacKepefC6sZdllg+7F57nnX37LyPCpcTr73bKpQufyJiufzp1sAPSy6cHUiVYb4ye6ronq99oUNsFxWlCbf4hF4vbl9Ssjlnevy1y7dHvz7EVH6yYuO182ceWltClLz7qumb1f4uj8PcwMb+qmMQNdw70grF9iQUiv4rLIftXFidO0p/n1mE6KmmozvWGza0fxwtBwx9z5zUkzo7o79sS1LTxX3rbmalnHhhsl7WuvZ3RtuOk2aestsdYVV5gYRLgbGKKNO9midVr44p0mSaalr1HLKNysm5a62iSzeIt9XtMBx8SMxT6xsZOSsso2hpUsuBxXufd5csXeFykV6+/kVKy9k1C++YFL2bbHsmVbHrIyJJt2MCZYdLPHqNbzpoUvkM/KXa+XlbVWN6dos01OyRbX7PyNjtmZ6x0LGg/6F884m1C6/HpS1Z5nMZU7HscWL7icAsSxJYuveJWtuKFZvvYOFwCZDuyoDopOcQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;&amp;yet story mode&quot;
        title=&quot;&quot;
        src=&quot;/static/7d1525e2a8f0510eded4f485e0d129ab/0a47e/andyet-story-mode.png&quot;
        srcset=&quot;/static/7d1525e2a8f0510eded4f485e0d129ab/29fe9/andyet-story-mode.png 151w,
/static/7d1525e2a8f0510eded4f485e0d129ab/6728c/andyet-story-mode.png 303w,
/static/7d1525e2a8f0510eded4f485e0d129ab/0a47e/andyet-story-mode.png 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We’ve been getting a lot of questions about the &lt;a href=&quot;http://andyet.com&quot;&gt;weird thing we’re doing on our home page&lt;/a&gt;. Most of them are some version of WTF? So I thought I’d share a little about what it is, why we’re doing it, and where it’s going.&lt;/p&gt;
&lt;p&gt;I believe strongly in the potential of digital spaces to foster amazing communities. So many of the people I care deeply about, I never would have met if it hadn’t been for Twitter and blogging and various pockets on the Internet. But 2016 feels like the year when so many of the places I’ve hung out have devolved drastically. Instead of feeling like a safe, exciting place full of amazing people, it’s started to feel like a company of strangers talking (often yelling) at the same time.&lt;/p&gt;
&lt;p&gt;It’s gotten me thinking about how to be more intentional about the way we connect with people online. Is it possible to do it better than we’re doing it now? How can we reject the defaults and assumptions of social media and invent our own way of being with others on the Internet?&lt;/p&gt;
&lt;p&gt;When I think about the times in my life when I’ve felt a deep sense of belonging, they are extremely rare. One of those times was last year’s &lt;a href=&quot;http://andyetconf.com&quot;&gt;&amp;#x26;yetConf&lt;/a&gt;. I wasn’t employed by &amp;#x26;yet at the time and I didn’t help out with the conference in any way. I was just a guest. But the event was so much more than an event for me…it was an experience that changed the way I thought about people, and about the things we can do together to create the future we want to live in. &lt;/p&gt;
&lt;p&gt;But mostly, it changed the way I thought about community. I remember standing in the lobby of Richland’s historic Uptown Theatre, looking around me at this eclectic mix of people interested in the same things I was, and thinking that I could stay in that moment for the rest of my life and be happy. We were all so different, and yet I belonged with every single one of those people.&lt;/p&gt;
&lt;p&gt;We didn’t have an &amp;#x26;yetConf this year (though I’m really pulling for us to do another one soon!). But I think that’s a good thing. My intense desire for that kind of community is challenging me to think about how we can do that on the Internet. We have so much technology and creativity at our disposal; surely we can create an experience that brings us together in a deeper way than we’ve previously been able to do online.&lt;/p&gt;
&lt;p&gt;So we wrote a story/play/RPG adventure, and then imagined how we could use it to introduce an experiment in community…something that brings us together to continue exploring the themes we started talking about at &amp;#x26;yetConf: the intersections between technology, humanity, meaning, and ethics. And we put it on our home page so no one could miss it.&lt;/p&gt;
&lt;p&gt;As far as for what’s happening next, most of that is a surprise. But I guarantee that if you are interested in the people part of technology (or if you like fun at all), you’re going to want to participate. And you know what? &lt;a href=&quot;http://andyet.com&quot;&gt;You should&lt;/a&gt;. Because it won’t be the same without you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[It's short for Captain EO]]></title><description><![CDATA[A little over a year ago, I stepped down as CEO at &yet, and Eric (at that time serving as our COO) took that position.Just recently, I've…]]></description><link>https://blog.andyet.com/2016/06/30/its-short-for-captain-eo/</link><guid isPermaLink="false">https://blog.andyet.com/2016/06/30/its-short-for-captain-eo/</guid><pubDate>Thu, 30 Jun 2016 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A little over a year ago, I stepped down as CEO at &amp;#x26;yet, and Eric (at that time serving as our COO) took that position.&lt;/p&gt;
&lt;p&gt;Just recently, I&apos;ve returned to the CEO role. I&apos;ve done so first and foremost at Eric&apos;s suggestion and request, yet I am also quite excited to be able to do so. (Eric has a blog post coming soon about this, too.)&lt;/p&gt;
&lt;p&gt;I am grateful for the significant effort Eric put into this role, in the organizational improvements he made during his time in it, and I&apos;m even more grateful that he is willing to resume carrying the responsibilities of being our COO. I have immense respect for Eric and for the work that he&apos;s done.&lt;/p&gt;
&lt;p&gt;When I stepped down, I did so in large part because I wanted to focus on the people of our organization and work to invest in and improve things for the individuals on our team. &lt;/p&gt;
&lt;p&gt;What I learned after just a brief time in that role is that because of the way &amp;#x26;yet historically worked and because of the uniqueness of my place in our structure, it wasn&apos;t really possible for me to do what I&apos;d hoped—especially as a former CEO—without undermining people, particularly Eric. I learned that as much as I just wanted to be a &quot;contributor&quot; and part of the team, being a former CEO &lt;em&gt;and&lt;/em&gt; owner makes it pretty much impossible to participate in that way. I am endlessly grateful for the incredible patience Eric demonstrated as I did my best to hold back expressing my opinions and to allow him to truly lead the company.&lt;/p&gt;
&lt;p&gt;I&apos;m also grateful that Amy—&amp;#x26;yet&apos;s longest tenured employee—was willing to seize the mantle of leading our &quot;People Ops&quot; role on the team and worked to help create a &quot;People Team&quot; which was able to carry out a good portion of what I aimed to do. Amy and the team who took on that set of responsibilities are amazing and I am exceedingly grateful for them.&lt;/p&gt;
&lt;p&gt;When I departed from this role, I considered my work in the CEO role a failure. I felt that I&apos;d not set the company up to succeed as well as I could have. I felt that my lack of focus and overconfidence in some aspects had created real hardship for people who I care about a great deal.&lt;/p&gt;
&lt;p&gt;Now, mind you, I&apos;m not terribly bothered by failure. There are so many good things that I can point to which are the result of difficult transitions that could be simply summed up as failures. But failing as an individual is different from failing as a leader of a team of people you care about. That&apos;s quite an emotional burden to carry around, but it&apos;s not one that I ever want to let go of. Leadership is serious business with real consequences. I&apos;m someone who seems to only learn the hard way, but I also know that I most definitely &lt;em&gt;do&lt;/em&gt; truly learn those lessons when I&apos;ve learned them the hard way!&lt;/p&gt;
&lt;p&gt;As I resume the responsibility for leading our company, I do so very humbly, and with a whole lot of things I&apos;ve learned in reflection during the past year, and in watching and learning from Eric, whose wisdom, steadiness, and pragmatism I really respect.&lt;/p&gt;
&lt;p&gt;I&apos;m proud of the 8 year adventure that &amp;#x26;yet has been—for the failures and successes both. I&apos;m especially grateful for the opportunity to work with every single person I&apos;ve had the privilege to work with in that time.&lt;/p&gt;
&lt;p&gt;Today, I&apos;m excited to again be leading this wonderful group of people and I’m looking forward to what we’re going to do together.&lt;/p&gt;
&lt;p&gt;Oh, and hey, this is a really good song:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/0qz0IJXQ720&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</content:encoded></item><item><title><![CDATA[hapi.js: Should It Be A Microservice? Decide Later]]></title><description><![CDATA[When building out an API for a service, you may find yourself building at least parts of an API you’ve already written before. You may find…]]></description><link>https://blog.andyet.com/2016/03/22/hapijs-microservice-decide-later/</link><guid isPermaLink="false">https://blog.andyet.com/2016/03/22/hapijs-microservice-decide-later/</guid><pubDate>Tue, 22 Mar 2016 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a76bcfa808a51c4a78817fd083f38c56/1cfc2/once-in-a-lifetime.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 39.735099337748345%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsSAAALEgHS3X78AAABGUlEQVQY01VQvUoEMRDex7lOBLU4C684EQ+9ZJJVsVK4QuE44bwk60+jb2BlKRYWYiWaTXZXUHwzZ5KNqzAM2ZnvbzaTxoMusQR1B8riW140oqjD3ApaOZEw6dPuFU0mjGeq5Mpx6pYbv3l0tzN9Gp89p+G/ggSWpsnQ+ReEC9AYxC+tDFc3DuXVF8nR1nGdhDSRmbKyqDOIU+qWI9PUg/2bXm95fTwfnTxAmytW8gjg3ITYaYcmdnBwuzY87o+m+fU3m79C6+kgeEKbjsA5OgtTxTCosjt72T59xJu3Jvei+OgM9d/jHe/I2qfYKFmJy08ks/O3Dh2ckwR1oJtLiX8bWnI8yTL1LnQFdEJkxoeFhY3D2NmiROcf41HmXTrmA8kAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Talking Heads -- Once in a Lifetime&quot;
        title=&quot;&quot;
        src=&quot;/static/a76bcfa808a51c4a78817fd083f38c56/90cbd/once-in-a-lifetime.png&quot;
        srcset=&quot;/static/a76bcfa808a51c4a78817fd083f38c56/29fe9/once-in-a-lifetime.png 151w,
/static/a76bcfa808a51c4a78817fd083f38c56/6728c/once-in-a-lifetime.png 303w,
/static/a76bcfa808a51c4a78817fd083f38c56/90cbd/once-in-a-lifetime.png 605w,
/static/a76bcfa808a51c4a78817fd083f38c56/1cfc2/once-in-a-lifetime.png 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When building out an API for a service, you may find yourself building at least parts of an API you’ve already written before. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You may find yourself&lt;br&gt;
In another part of the world &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is often the time you should write it as a microservice and share it between several apps, right? &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Letting the days go by&lt;br&gt;
Let the water hold me down&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well, if you’re writing your API in &lt;a href=&quot;https://nodejs.org/&quot;&gt;NodeJS&lt;/a&gt; with &lt;a href=&quot;http://hapijs.com&quot;&gt;hapi.js&lt;/a&gt;, you could just publish your microservice as a private module, and decide later. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You may ask yourself&lt;br&gt;
Well, how did I get here?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Try using a controller pattern, and loading the controller as a hapi.js plugin.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You may ask yourself&lt;br&gt;
How do I work this?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The root of an npm package is typically index.js, although you can change this in package.json by setting “main” to another file. Set up your server.js as the script that loads all of your hapi.js plugins and starts the HTTP service, and setup index.js as a hapi.js plugin that takes your configuration as options and sets up all of the routes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Letting the days go by&lt;br&gt;
Water flowing underground &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let’s say that one of the requirements for your project was the ability to have user comments.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;./package.json&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@fritzy/comments&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;index.js&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;./server.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&apos;use strict&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;getconfig&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Hapi &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;hapi&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; server &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Hapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Server&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    register&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;good&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    options&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      reporters&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        reporter&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;good-console&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        events&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          response&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          log&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;*&apos;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// here we require our microservice as a controller&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// you&apos;d require(&apos;@fritzy/comments&apos;) in any other project&lt;/span&gt;
    register&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./index&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    options&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; config
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// something bad happened loading the plugin&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;info&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Server running at: &apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;info&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uri&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;./index.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&apos;use strict&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Comments &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./handlers/comments&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// options is the config that we passed in server.js&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;plugin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;pg&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;db&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;plugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    db&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; db
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  
  plugin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    method&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;get&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    config&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Comments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;list
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  plugin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    method&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;get&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/{id}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    config&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Comments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  plugin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    method&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;post&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    config&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Comments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;create
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  plugin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    method&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;put&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/{id}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    config&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Comments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;update
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  plugin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    method&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;delete&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/{id}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    config&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Comments&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;delete
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;And you may ask yourself&lt;br&gt;
Where is that large automobile? &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now you can publish this project as a private npm package, and require it in your larger project. In fact, you can require it any of your future projects whenever you need comments. If you decide later to make it a microservice, simply deploy it by itself (running the server.js).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;And you may tell yourself&lt;br&gt;
This is not my beautiful house &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When you register the &lt;code class=&quot;language-text&quot;&gt;@fritzy/comments&lt;/code&gt;  in your larger project’s &lt;code class=&quot;language-text&quot;&gt;server.js&lt;/code&gt; , here is what it’ll look like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    register&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;@fritzy/comments&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    routes&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      prefix&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/comments&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    options&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; config
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;And you may tell yourself&lt;br&gt;
This is not my beautiful wife  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You now have a lot of extra flexibility in scaling, re-using code, and production operations styles for your microservice/module/plugin.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Same as it ever was&lt;br&gt;
Same as it ever was &lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;If you have any thoughts or feedback, poke me on &lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;Twitter @fritzy&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;We&apos;d love to help you with your &lt;a href=&quot;https://nodejs.org&quot;&gt;NodeJS&lt;/a&gt; project, so &lt;a href=&quot;https://andyet.com/contact&quot;&gt;drop us a line&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Design for Developers, Part 1: Why?]]></title><description><![CDATA[Last month Lynn introduced a blog series, Design for Developers, which we’re super excited about. In upcoming posts, you can expect to learn…]]></description><link>https://blog.andyet.com/2016/03/16/design-for-developers-part-1-why/</link><guid isPermaLink="false">https://blog.andyet.com/2016/03/16/design-for-developers-part-1-why/</guid><pubDate>Wed, 16 Mar 2016 01:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/34c0fe89c93f8aab099e45924eaa0214/1cfc2/blog-why-design-900.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 38.41059602649007%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsSAAALEgHS3X78AAABK0lEQVQY06VR3U/CMBzk/380TObcpPvQmGg0QwLRxAcfZQwT3NRBt7aAMFi27ttX20Fi4qMml0vv1979kmtLR9Wf0TJIreNaR5w1xqgycG3gL8ZaUBmN1IJSZ8DsXKl+qSE+52b5LepYgWxj4IYXXiSMAnG6kdyt7G5Fyz8aIWGyFG3SfoYdmzB5YvmqG3Y9ys3sTrbR07p8WJV3KO35SZ/kl0Fukvx+kV3Pox7O+oviBsa9IDX92MSZSQoAi2azuxMsdAsTNjWc9QCnQ5Kez6mJ0gFiQdmA5Cz0cZmxLBNGV5BqMwrmGTerMBfGRLAXkrvrvKzAjHZfN5KzPfOS48lS+YgVL1E8qr7vlOlne4xOnRB4FMDGzHvjDf3gl9xDw4deD2/2hf3nq74B46GFx1JOXAcAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Why design?&quot;
        title=&quot;&quot;
        src=&quot;/static/34c0fe89c93f8aab099e45924eaa0214/90cbd/blog-why-design-900.png&quot;
        srcset=&quot;/static/34c0fe89c93f8aab099e45924eaa0214/29fe9/blog-why-design-900.png 151w,
/static/34c0fe89c93f8aab099e45924eaa0214/6728c/blog-why-design-900.png 303w,
/static/34c0fe89c93f8aab099e45924eaa0214/90cbd/blog-why-design-900.png 605w,
/static/34c0fe89c93f8aab099e45924eaa0214/1cfc2/blog-why-design-900.png 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Last month &lt;a href=&quot;https://andyet.com/team/lynn/&quot;&gt;Lynn&lt;/a&gt; introduced a blog series, &lt;a href=&quot;https://blog.andyet.com/2016/02/16/design-for-devs-where-to-start/&quot;&gt;Design for Developers&lt;/a&gt;, which we’re super excited about. In upcoming posts, you can expect to learn things like how to tackle the fear of the ‘blank canvas’, how to use typography effectively, and how to customize and extend commonly used design patterns in frameworks like Bootstrap.&lt;/p&gt;
&lt;p&gt;But today we’re taking a step back and starting with a more fundamental question - raised by our friend Ivana McConnell on &lt;a href=&quot;https://twitter.com/IvanaMcConnell/status/699994728843120640&quot;&gt;twitter&lt;/a&gt; - which is basically: “Why?”. Why should a developer learn design? This is a fabulous question! Thanks Ivana for reaching out!&lt;/p&gt;
&lt;h2 id=&quot;why-does-anyone-decide-to-do-anything&quot;&gt;&lt;a href=&quot;#why-does-anyone-decide-to-do-anything&quot; aria-label=&quot;why does anyone decide to do anything permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why does anyone decide to do anything?&lt;/h2&gt;
&lt;p&gt;In pondering this question of “Why”, I’m reminded of a &lt;a href=&quot;https://medium.com/@dark_roast_ruth/goal-setting-in-a-world-that-wants-you-to-feel-guilty-about-everything-3c0c0b21ff66#.k3fix17x8&quot;&gt;post&lt;/a&gt; by Ruth Baril where she talks about achieving some amazing goals in life, but really only found success when she was able to identify the true reasons for even attempting these goals in the first place. Just as there are infinite reasons one may choose to lose weight, move across the country, or take on any new skill, there are many different but legitimate reasons for developers to learn design. Here, we’ll point out a few and hopefully one (or several!) will resonate with you.&lt;/p&gt;
&lt;h2 id=&quot;8-reasons-developers-can-and-should-learn-design&quot;&gt;&lt;a href=&quot;#8-reasons-developers-can-and-should-learn-design&quot; aria-label=&quot;8 reasons developers can and should learn design permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;8 Reasons developers can and should learn design&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1: It’s fun&lt;/strong&gt;
I know there’s a common stereotype of the ‘serious’ designer agonizing over the tiniest of spaces between things when you’re just ready to &lt;em&gt;ship the thing already&lt;/em&gt;, and you may think, “How is this fun?”. But like many things in life, there are many sides to the same task. If obsessing over singular pixels of whitespace doesn’t excite you, know that there are many other aspects of design that are so fun!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You get to play with color and shapes and typography. And when I say ‘play’, I really mean it!&lt;/li&gt;
&lt;li&gt;You’re solving problems.&lt;/li&gt;
&lt;li&gt;You get to see visual evidence of your hard work.&lt;/li&gt;
&lt;li&gt;Designing can be very social. Whether it be user testing or seeking feedback from peers, discussion is often a huge part of a successful design process.&lt;/li&gt;
&lt;li&gt;You get to think of something and watch it come to life - like playing god, on a smaller (but still thrilling) scale.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And yes, sometimes you do have to push singular pixels around, but there’s an endgame. And the payoff is hugely rewarding, and yes it’s enormously fun to see people light up and enjoy what you’ve built. Design can do that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2: It makes your work &lt;em&gt;work&lt;/em&gt; better&lt;/strong&gt;
Good usability, which is essentially what we are all striving for regardless of our background, goes so much deeper than sheer functionality. A product may function flawlessly, but unless the user enjoys interacting with product, it’s virtually useless. All you have to do is comment out the CSS reference in any site to see the importance of design in usability. Learning even basic design concepts like balance and hierarchy can improve user experience for your product immensely. Learning these concepts teaches you to put yourself in the user’s shoes and can make you empathize with the user in a whole new way. Design helps you shift from a mindset of outputting data to presenting the data in a way that is meaningful to the user.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3: Money?&lt;/strong&gt;
You know what happens when your product works better? People pay you more for it. Moving on…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4: It makes you a better teammate&lt;/strong&gt;
It’s this reason here which resonates most with me. At &amp;#x26;yet we work very hard to nurture strong bonds across our multi-disciplinary team. In our recent &lt;a href=&quot;http://createsend.com/t/r-6C4ADAFBE3116E7C2540EF23F30FEDED&quot;&gt;&amp;#x26;you dispatch&lt;/a&gt; we discuss alignment and the challenge that comes with bringing different perspectives, and sometimes different goals, to the same task. Understanding the perspective of a designer, and even just the vocabulary that goes along with the practice of design, can help improve communication and make you such a valuable ally to the design team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5: It makes you more hirable&lt;/strong&gt;
If what you need right now is to carve a niche or stand out in a sea of applicants, consider adding design to your list of skills. These days, it’s no secret that design and programming is an intrinsically connected process. Companies are increasingly aware of the importance of hiring workers who can cross disciplines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6: It’s gratifying&lt;/strong&gt;
As mentioned in point #1, watching people respond positively to design choices can be very rewarding. Yes, pure programming can be gratifying in a similar way, but making concerted design choices can elicit emotional responses to seemingly mundane user interactions in a way that nothing else can.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7: You can be more self-reliant&lt;/strong&gt;
If your process involves handing off your work to a designer, it could benefit you greatly to have the ability to anticipate how a designer might handle something so that you have to hand off less and less of the project, saving you time and/or money - particularly if you work solo or are not part of a cross-disciplinary team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;8: You’re already designing&lt;/strong&gt;
The minute you output data into a view you’re thrust into a position where you must make design decisions. Learning the basics of design can help you bridge the gap between form and function in a way that is super empowering and builds on your existing skills.&lt;/p&gt;
&lt;h2 id=&quot;whatd-we-forget&quot;&gt;&lt;a href=&quot;#whatd-we-forget&quot; aria-label=&quot;whatd we forget permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’d we forget?&lt;/h2&gt;
&lt;p&gt;Can you think of any reasons that developers should learn design skills that we didn’t put on the list? &lt;a href=&quot;https://twitter.com/andyet&quot;&gt;Tweet&lt;/a&gt; at us and let us know!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[It's our Birthday!]]></title><description><![CDATA[February 28th marks the completion of 8 years of &yet being in business. Being a Leap Year, we realized we missed a great opportunity to…]]></description><link>https://blog.andyet.com/2016/02/26/its-our-birthday/</link><guid isPermaLink="false">https://blog.andyet.com/2016/02/26/its-our-birthday/</guid><pubDate>Fri, 26 Feb 2016 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a44d7f4e4b63ca383d538733dc183549/1cfc2/yeti-versary-8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 78.80794701986756%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAIAAACZeshMAAAACXBIWXMAAAsSAAALEgHS3X78AAACM0lEQVQoz2VTS4sTQRDOz/BP+DM8CuLRgydPIqIXTyJ49bQ3lQVP4mMXIXsxoAsLIrKCqETWxI0xr00mk8w78+qe6S6/6klishZF011VX727RqWiMKU4p0TwuQBnFG1zaE7Ioa0sg5QyWWNpJsmOaBqyThQkS1KalCKQNgzCEypY+gkNPeMxNWAExzmLqD8nK2C2Q43TjbUdlU68FE58GrpQkRdXEAMuShNEM4tCplIFCSc2XwgnLmYhmM1SyZaqyoQ2IkMEl1PjFXIvbFsuLvDafvDYelbHRa9h+hwYdSKxMNXITelUyrtH7U+7n/UwON19M3vZQAO4B37K3T0fGTxBVUHpLCCXRO/v1H/ePJhc3Q9sRwkhSs3glkWn021wVXPB8YXSZc7Pyb131q234+v1yEUupUCyiNkc0bfBMvgKrGiDCq0ReXC70and9/aasUhEZKwxi7FPP87oZPwfWJTQaYwRyJ2P3RsH2cA9u/RicOXVAtkicm/O00Z3ftvbNcPr1z715rpjU3/Wf3TUvPY6Gjndi096F3aEGQFXW7W2swnGxqHJlk9+zAs0cpUfdx8eti4/n+59nz89dupNk7azXGGsCrYtYHBKSc49wzsHS5LFsoUr0tJoIcyNjTBPP6lxGZHZ+DUHGbyqMNNeyl8CqwYDN+bLYvVzIM/xMTbJ7JD+Yp80Roc5OX88DEYfd6k1oQ+/GF9t8Ypq/9Zt7UGUbihTrCymgCLxkzjVYhNWof4C0XyJNvpabtQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;it&apos;s our birthday&quot;
        title=&quot;&quot;
        src=&quot;/static/a44d7f4e4b63ca383d538733dc183549/90cbd/yeti-versary-8.png&quot;
        srcset=&quot;/static/a44d7f4e4b63ca383d538733dc183549/29fe9/yeti-versary-8.png 151w,
/static/a44d7f4e4b63ca383d538733dc183549/6728c/yeti-versary-8.png 303w,
/static/a44d7f4e4b63ca383d538733dc183549/90cbd/yeti-versary-8.png 605w,
/static/a44d7f4e4b63ca383d538733dc183549/1cfc2/yeti-versary-8.png 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;February 28th marks the completion of 8 years of &amp;#x26;yet being in business. Being a Leap Year, we realized we missed a great opportunity to make our company’s inception date February 29th.&lt;/p&gt;
&lt;p&gt;At this point in our company&apos;s history, we&apos;re very excited to say this is our 8th birthday! We&apos;re the 8 year old that is excited about being a year older! And wiser! And better at things! Because that&apos;s what comes with age, right?&lt;/p&gt;
&lt;p&gt;Almost universally, that&apos;s exactly what comes with age. Of course, those things don&apos;t come to us by simply watching time pass, it&apos;s what happens during that time that we earn additional wisdom, skill, and experience. A number of things have happened in the past year that I firmly believe will make us wiser and stronger as we proceed into the years to come.&lt;/p&gt;
&lt;p&gt;We put on an amazing conference this fall that put a unique and extremely powerful spin on your typical tech conference. Folks who attended have eagerly referred to it as life-altering and intensely motivating. We&apos;re so fortunate to have the friends who, old and new, share our vision for the world and pitched in to pull it off.&lt;/p&gt;
&lt;p&gt;For the first time in our company&apos;s history, the CEO is not named Adam Brault. Adam decided it was time for him to take a different role in the company, and promoted me to the CEO role. The team, Adam, and I have been adjusting to this transition, but we all feel this marks an exciting next phase of the company&apos;s maturation. And I&apos;m certainly excited about this new role!&lt;/p&gt;
&lt;p&gt;The year was not without challenges. We hit a slow period of business and were forced to let go of some team members, and especially in our close-knit group, that&apos;s an incredibly painful thing to go through. But with every challenge comes opportunity, and I think we gained some valuable experience and knowledge from that period.&lt;/p&gt;
&lt;p&gt;Looking forward, we&apos;re excited about a number of things in the coming year: our &lt;a href=&quot;https://talky.io/&quot;&gt;Talky Core&lt;/a&gt; offering, &lt;a href=&quot;https://nodesecurity.io/&quot;&gt;the Node Security Platform&lt;/a&gt;, and new opportunities to &lt;a href=&quot;https://andyet.com/&quot;&gt;build amazing things&lt;/a&gt; for awesome clients. We have a lot to be thankful for, but most of all, we&apos;re so lucky to get to meet and interact with and work with all of you. We believe software is about people, so to be able to keep doing what we do is extremely fulfilling for this 8 year old.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Generating URL-Safe Short IDs in Postgresql]]></title><description><![CDATA[In Postgresql, generally an incrementing primary key is used, which  is an excellent helper type for.
Sometimes though, an incrementing ID…]]></description><link>https://blog.andyet.com/2016/02/23/generating-shortids-in-postgres/</link><guid isPermaLink="false">https://blog.andyet.com/2016/02/23/generating-shortids-in-postgres/</guid><pubDate>Tue, 23 Feb 2016 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/73f9f96748e214296d46a795241cdddb/21b4d/postgres-short-id-footer.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 54.966887417218544%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsSAAALEgHS3X78AAABuUlEQVQoz12S54oCUQyF5/0fwQcQBBEUsSD23nuvvyxYsGPP8mWZWdlAZu7NTU5OivH5fMSU1+ul/8fjIbPZTIbDodxuN/kvxKD3+11Op5NMp1N5Pp/6ZvDBaBrO57NEo1HJ5XLSbDYlHo9LuVyWbrcrk8lEDoeDlbzRaKhPPp+37AaZ2u22BpIpm81KKBRS52KxKIlEQpxOp9hsNkmlUpLJZGS1WmkwMf1+X20Ak0QZkj2ZTFqKI2CBQEDPMIA1SWq1mvpDBLDlcqlERqORLBaLv5JxIhOlwpJztVrVu9frVUBsbrdbBoOBAgEC216vp6D01DCHQu8A8Pl8Ckh5sDVZAcwb4JvNRo7How5uu93Ker3WQVpD+Z50p9MRu90uwWBQgbkTWKlUxOVyaQu+/S+Xi7JF3u/3L0OUC3K9XpUZbL+Fd8DNYFNg9r1axv8dY30Iojf0ltL2+722hNXgv9vtZD6fa1KUCrjzZozHYwmHw+L3+yUWi0kkEtFyKa1QKGgAPWQXOVM6fgyJOPrqcDjE4/FoZQpIKTTfHABar9d1dViZUqmk+8iuMWFsaKvVEuJZH+7pdFp+AGrtFy+BnjxLAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;postgres elephant words&quot;
        title=&quot;&quot;
        src=&quot;/static/73f9f96748e214296d46a795241cdddb/90cbd/postgres-short-id-footer.png&quot;
        srcset=&quot;/static/73f9f96748e214296d46a795241cdddb/29fe9/postgres-short-id-footer.png 151w,
/static/73f9f96748e214296d46a795241cdddb/6728c/postgres-short-id-footer.png 303w,
/static/73f9f96748e214296d46a795241cdddb/90cbd/postgres-short-id-footer.png 605w,
/static/73f9f96748e214296d46a795241cdddb/a2b88/postgres-short-id-footer.png 908w,
/static/73f9f96748e214296d46a795241cdddb/a3767/postgres-short-id-footer.png 1210w,
/static/73f9f96748e214296d46a795241cdddb/21b4d/postgres-short-id-footer.png 1280w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;http://www.postgresql.org/&quot;&gt;Postgresql&lt;/a&gt;, generally an incrementing primary key is used, which &lt;code class=&quot;language-text&quot;&gt;SERIAL&lt;/code&gt; is an excellent helper type for.
Sometimes though, an incrementing ID exposed in an API or URLs reveals too much about the service, like the number of users you have (see the &lt;a href=&quot;https://en.wikipedia.org/wiki/German_tank_problem&quot;&gt;German Tank Problem&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;You could use &lt;a href=&quot;https://en.wikipedia.org/wiki/Universally_unique_identifier&quot;&gt;UUIDs&lt;/a&gt; for this, but they&apos;re long and obnoxious if you&apos;re exposing them to a user via URLs.
Instead, we want a short string, say 8 characters in length, that is &lt;a href=&quot;https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator&quot;&gt;a cryptographically-secure, random&lt;/a&gt; value. We need a cryptographically-secure generator because otherwise someone could guess the generator algorithm, seed the previous value, and we&apos;d again be vulnerable to the German Tank Problem.&lt;/p&gt;
&lt;p&gt;Postgresql comes with an extension called &lt;a href=&quot;http://www.postgresql.org/docs/current/static/pgcrypto.html&quot;&gt;pgcrypto&lt;/a&gt; that has a &lt;code class=&quot;language-text&quot;&gt;generate_random_bytes&lt;/code&gt; function.
We&apos;ll use this to generate 6 bytes, giving us 2^48 possible keys, and then encode them in &lt;a href=&quot;https://en.wikipedia.org/wiki/Base64#URL_applications&quot;&gt;URL-safe Base64&lt;/a&gt;.
The &lt;a href=&quot;https://en.wikipedia.org/wiki/Birthday_problem#Probability_table&quot;&gt;Birthday Problem probability table&lt;/a&gt; says that we can expect a 1% chance of having had a collision once we&apos;ve generated 240,000 IDs, 25% after 1,300,000 IDs, and 50% at 20,000,000 IDs.
So even after 20,000,000 IDs generated, we may only have had 1 collision.
We&apos;ll use a &lt;code class=&quot;language-text&quot;&gt;LOOP&lt;/code&gt; just in case we hit a collision.&lt;/p&gt;
&lt;p&gt;First, let&apos;s make sure &lt;code class=&quot;language-text&quot;&gt;pgcrypto&lt;/code&gt; is loaded.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; EXTENSION &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pgcrypto&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then, we&apos;ll write a &lt;a href=&quot;http://www.postgresql.org/docs/current/static/plpgsql-trigger.html&quot;&gt;Trigger Procedure&lt;/a&gt; which generates a random key and ensures that it is unique to a table.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;-- Create a trigger function that takes no arguments.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- Trigger functions automatically have OLD, NEW records&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- and TG_TABLE_NAME as well as others.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; unique_short_id&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$

 &lt;span class=&quot;token comment&quot;&gt;-- Declare the variables we&apos;ll be using.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;DECLARE&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  qry &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  found &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;-- generate the first part of a query as a string with safely&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;-- escaped table name, using || to concat the parts&lt;/span&gt;
  qry :&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;SELECT id FROM &apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; quote_ident&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TG_TABLE_NAME&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos; WHERE id=&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;-- This loop will probably only run once per call until we&apos;ve generated&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;-- millions of ids.&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;LOOP&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;-- Generate our string bytes and re-encode as a base64 string.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt; :&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; encode&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gen_random_bytes&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;base64&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;-- Base64 encoding contains 2 URL unsafe characters by default.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- The URL-safe version has these replacements.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt; :&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;_&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;-- url safe replacement&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt; :&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;+&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;-&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;-- url safe replacement&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;-- Concat the generated key (safely quoted) with the generated query&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- and run it.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- SELECT id FROM &quot;test&quot; WHERE id=&apos;blahblah&apos; INTO found&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- Now &quot;found&quot; will be the duplicated id or NULL.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; qry &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; quote_literal&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; found&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;-- Check to see if found is NULL.&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- If we checked to see if found = NULL it would always be FALSE&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- because (NULL = NULL) is always FALSE.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; found &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt;

      &lt;span class=&quot;token comment&quot;&gt;-- If we didn&apos;t find a collision then leave the LOOP.&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;EXIT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;-- We haven&apos;t EXITed yet, so return to the top of the LOOP&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- and try again.&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;LOOP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;-- NEW and OLD are available in TRIGGER PROCEDURES.&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;-- NEW is the mutated row that will actually be INSERTed.&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;-- We&apos;re replacing id, regardless of what it was before&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;-- with our key variable.&lt;/span&gt;
  NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;-- The RECORD returned here is what will actually be INSERTed,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;-- or what the next trigger will get if there is one.&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;language&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;plpgsql&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Replace &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt; in the select, and &lt;code class=&quot;language-text&quot;&gt;NEW.id&lt;/code&gt; with whatever your &lt;code class=&quot;language-text&quot;&gt;PRIMARY KEY&lt;/code&gt; is called.&lt;/p&gt;
&lt;p&gt;Now let&apos;s hook this &lt;code class=&quot;language-text&quot;&gt;Trigger&lt;/code&gt; up to a &lt;code class=&quot;language-text&quot;&gt;Table&lt;/code&gt; to execute whenever there is an &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; test &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;-- We name the trigger &quot;trigger_test_genid&quot; so that we can remove&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- or replace it later.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- If an INSERT contains multiple RECORDs, each one will call&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;-- unique_short_id individually.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; trigger_test_genid BEFORE &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; test &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PROCEDURE&lt;/span&gt; unique_short_id&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&apos;ll note that we want &lt;code class=&quot;language-text&quot;&gt;unique_short_id&lt;/code&gt; to trigger before the &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt; is finalized, so that we can replace the &lt;code class=&quot;language-text&quot;&gt;PRIMARY KEY&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, whenever we &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt;, our &lt;code class=&quot;language-text&quot;&gt;Trigger Procedure&lt;/code&gt; will run and generate a unique ID.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; test &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;cheese&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ham&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;turkey&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;chicken&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; test&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;txt&quot;&gt;&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;    id    |  name
----------+---------
 Ixw1yIj7 | cheese
 SXq0jZ-q | ham
 KKWXEtBu | turkey
 DRRXFs1U | chicken
(4 rows)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&apos;ve got short, URL-safe, unique IDs that we can expose in APIs and URLs that don&apos;t reveal any information and aren&apos;t cumbersome or ugly.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Update: &lt;a href=&quot;https://twitter.com/lancestout&quot;&gt;@lancestout&lt;/a&gt; points out that there is a chance of producing swear words.
You could search a blacklist of words allowing for mutations, but maybe it&apos;d be easier to encode it as hex instead of base64 with: &lt;code class=&quot;language-text&quot;&gt;encode(gen_random_bytes(6), &amp;#39;hex&amp;#39;)&lt;/code&gt;.
The downside of using hex is that encoding 6 bytes takes around 12 characters.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you&apos;d like assistance in your web applications and APIs, &lt;a href=&quot;https://andyet.com/contact&quot;&gt;let us know!&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Design for Developers and Where to Start]]></title><description><![CDATA[I talk a lot about designers learning development and in most discussions someone will inevitably ask, “Well, should developers learn design…]]></description><link>https://blog.andyet.com/2016/02/16/design-for-devs-where-to-start/</link><guid isPermaLink="false">https://blog.andyet.com/2016/02/16/design-for-devs-where-to-start/</guid><pubDate>Tue, 16 Feb 2016 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e9e76ad937c9bd04688f66e005773cf8/1cfc2/design-shrug.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 56.29139072847682%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsSAAALEgHS3X78AAACfElEQVQoz22T30uTURjH/RO6kS4j6KI/IYToRvQiL5RNL4IoupBAYxAmKpixKCNtQdmWbjqpiH6JGVnO0X45yylO9+p+bzo39+v1dT/c2jTk/XbOYRuOujg85zw87+d8v89z3po9Yf+YLAj7KXE/lUYsnqB7JJI8XG4P3B4vfD4/1tYccHAbLM/vCUilM8ge5EC/pWca6aohh2MKICBx+vMMrNafDOjzB7BkW4ZlwYp5/Q8WA8EtRGNxGAwm6Ob1MFsWmICT0Cogt7EJqnJrO4TQThg22wqaWyRolUggkbYxKK2lyp0uNzxeHwOlM1mWp/uasmWSFHP534jsRhGJ7OIgn8ed7h503GjFlEZOYht6+/oRLbUkye8xAK2nbnajMZavANcdnDj77Tuzt+l0EWAB4+qXUD6UQaPoxWBfOxTDQwxoIVb1pM5gNMFktmBON8/aQd0xIL2JyBcJFMFgELFEErnCISa1E9AqurA4rcDI/Q6oRtXMntPtRSDgRzgcYaqqLNMe0k2+UBQ5xzpUigGYZ9TIH2QxohyFtOUylMM9qG9swMepaRSP/sBh/YLJETlMBj0y2RySpclXDYVMT6S9iEe28UT1HIurdoyPqXHh2k2o3ipxpkOOBwMD8IfCePTiGVwbdnjJUMrK/gv0b4WAoyJuza7h9hwHqeI1LsnuQtbdhYuDWtS1d+Oezo7m98tI8zx2ItHKk6kAy0MhS0wKKRRTAoaWAjg3ZkXtxCrqNEZIG+rR9HgStR+COKsy4spXjtXR+pOPuqKwdIuY4AUUMmm8Wnbj1BsPGt/9wnmNFZ3Xr6Kp/ymaPq3gtNaOTh2Hw0wKcV7450/5C6dO4Qc0X26SAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Design for Developers&quot;
        title=&quot;&quot;
        src=&quot;/static/e9e76ad937c9bd04688f66e005773cf8/90cbd/design-shrug.png&quot;
        srcset=&quot;/static/e9e76ad937c9bd04688f66e005773cf8/29fe9/design-shrug.png 151w,
/static/e9e76ad937c9bd04688f66e005773cf8/6728c/design-shrug.png 303w,
/static/e9e76ad937c9bd04688f66e005773cf8/90cbd/design-shrug.png 605w,
/static/e9e76ad937c9bd04688f66e005773cf8/1cfc2/design-shrug.png 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;figcaption&gt;Infomercial narration voice: Is this you when it comes to design?&lt;/figcaption&gt;
&lt;p&gt;I talk a lot about designers learning development and in most discussions someone will inevitably ask, “Well, should developers learn design?” And to that I say, “Absolutely.”&lt;/p&gt;
&lt;p&gt;A great deal of development work already &lt;em&gt;is&lt;/em&gt; design work (don’t let anyone tell you differently). But I also know developers want to improve their visual design, UX, typography, and illustration skills. Here’s some tips on how to get started. Spoiler: They’re all things you can already do.&lt;/p&gt;
&lt;h2 id=&quot;decide&quot;&gt;&lt;a href=&quot;#decide&quot; aria-label=&quot;decide permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decide&lt;/h2&gt;
&lt;p&gt;The first step is to decide to be a designer. It’s possible to design things without realizing it. But it doesn’t do any good designing things and continuing to deny that’s what you’re doing. Decide to be a designer and design &lt;em&gt;with&lt;/em&gt; purpose and &lt;em&gt;on&lt;/em&gt; purpose.&lt;/p&gt;
&lt;h2 id=&quot;start&quot;&gt;&lt;a href=&quot;#start&quot; aria-label=&quot;start permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Start&lt;/h2&gt;
&lt;p&gt;Where do you start? Anywhere. There’s no standard curriculum or single point of entry. Pick a thing that interests you and start there. Don’t worry about what you need to know “first.”&lt;/p&gt;
&lt;h2 id=&quot;but-maybe-start-small&quot;&gt;&lt;a href=&quot;#but-maybe-start-small&quot; aria-label=&quot;but maybe start small permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But maybe start small&lt;/h2&gt;
&lt;p&gt;Just like with development, there’s a lot out there to learn and even more you may not need right now. It’s easy to be overwhelmed. Create content or time constraints to make things more manageable. Pick a tiny portion of a larger concept to focus on or set aside 10 minutes each day to read about a specific topic.&lt;/p&gt;
&lt;h2 id=&quot;practice&quot;&gt;&lt;a href=&quot;#practice&quot; aria-label=&quot;practice permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Practice&lt;/h2&gt;
&lt;p&gt;Practice makes better. Just like with development, you’ll learn how to make design decisions through repetition, experimenting, and of course by making mistakes. &lt;/p&gt;
&lt;h2 id=&quot;recognize-shared-values&quot;&gt;&lt;a href=&quot;#recognize-shared-values&quot; aria-label=&quot;recognize shared values permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Recognize shared values&lt;/h2&gt;
&lt;p&gt;Here’s a not-so-secret secret: The skills, practices, and values that make you a great developer are what make a great designer, too. Think of the things you prioritize that make your code better. Things like consistency and modularity. You want your code to have clear hierarchy, to be readable and easily understood. It should be flexible, testable, and accessible. Designers prioritize these same values when creating solid user experiences, interfaces, style guides, and brand identities. We have much more in common than you might think.&lt;/p&gt;
&lt;h2 id=&quot;talk-to-designers&quot;&gt;&lt;a href=&quot;#talk-to-designers&quot; aria-label=&quot;talk to designers permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Talk to designers&lt;/h2&gt;
&lt;p&gt;If you’re still skeptical of where these commonalities lie, try talking to designers. Really. Turns out people like to talk about their work and passions, so ask. And then listen. A big part in learning anything is understanding and appreciating those who do it. And this has a cool ripple effect. The second you ask someone to help you learn, you’ve turned them into a teacher.&lt;/p&gt;
&lt;h2 id=&quot;partner-up&quot;&gt;&lt;a href=&quot;#partner-up&quot; aria-label=&quot;partner up permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Partner up&lt;/h2&gt;
&lt;p&gt;If you can, find a designer who also wants to learn about development. Team up on some projects where you can help each other grow. Find out how the decisions you both make affect each other’s work. Think about how your unique perspective can impact theirs and vice versa.&lt;/p&gt;
&lt;h2 id=&quot;show-others-your-work&quot;&gt;&lt;a href=&quot;#show-others-your-work&quot; aria-label=&quot;show others your work permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Show others your work&lt;/h2&gt;
&lt;p&gt;This might be the scariest one. When you design something, show someone. Ask for feedback. Things may not feel finished or good enough to show, but that’s the time you most need to. I’ve been stuck on this quote by &lt;a href=&quot;https://andyet.com/team/gar/&quot;&gt;Gar&lt;/a&gt; for years:&lt;/p&gt;
&lt;blockquote&gt;“Only those who are willing to take the risk of writing code that’s not perfect ever write code.”&lt;/blockquote&gt;
You’re already sharing your code in various states of “done”; apply that same mindset to your design work.
&lt;h2 id=&quot;stop-apologizing&quot;&gt;&lt;a href=&quot;#stop-apologizing&quot; aria-label=&quot;stop apologizing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Stop apologizing&lt;/h2&gt;
&lt;p&gt;Avoid the temptation to preface your work, questions, or discussions with “Sorry, I’m not a designer…” &lt;strong&gt;Stop apologizing.&lt;/strong&gt; “You’re not a real designer unless you [insert some arbitrary condition].” Don’t say this to yourself and don’t let others say it to you. We define who we are and what we’re good at. If you’re designing things, you’re a designer.&lt;/p&gt;
&lt;h2 id=&quot;level-up&quot;&gt;&lt;a href=&quot;#level-up&quot; aria-label=&quot;level up permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Level up&lt;/h2&gt;
&lt;p&gt;Here’s the thing. As you do the things listed above and learn more about design, you’ll become a more versatile, empathetic, and well-rounded developer, too. &lt;/p&gt;
&lt;h2 id=&quot;what-topics-interest-you&quot;&gt;&lt;a href=&quot;#what-topics-interest-you&quot; aria-label=&quot;what topics interest you permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What topics interest you?&lt;/h2&gt;
&lt;p&gt;This is the first of a Design for Developers blog series the &amp;#x26;yet design team plans to write and we’d love your thoughts. What kinds of topics are you interested in? What write-ups or tutorials would help you in your learning? &lt;a href=&quot;https://twitter.com/andyet&quot;&gt;Share your ideas with us on Twitter!&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Node.js Is For Middleware]]></title><description><![CDATA[yetis talk through node in different languagesNode.js is an ideal middleware solution for enterprises, with its accessible JavaScript, event…]]></description><link>https://blog.andyet.com/2016/02/09/node-is-for-middleware/</link><guid isPermaLink="false">https://blog.andyet.com/2016/02/09/node-is-for-middleware/</guid><pubDate>Tue, 09 Feb 2016 13:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cldup.com/jfZEdodB43.png&quot; alt=&quot;yetis talk through node in different languages&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nodejs.org&quot;&gt;Node.js&lt;/a&gt; is an ideal middleware solution for enterprises, with its accessible JavaScript, event system, and vast range of libraries for working with data.&lt;/p&gt;
&lt;p&gt;Sure, HTTP is a first class citizen for Node.js, but so are raw sockets and files. Compare this to Rails, which was for building dynamic sites, or Django&apos;s original focus on building content management systems. And sure, often times Node.js is the middleware that connects a database and a website (both realtime and not), but it&apos;s also great at connecting all sorts of static and evented systems together.&lt;/p&gt;
&lt;p&gt;The battle for middleware has always been configuration versus scripting. With products like Oracle Data Integrator, Apigee&apos;s API Exchange, and many others, they lean all of the way toward configuration. But if you&apos;ve ever used one of these projects, learning the conventions of the configuration is akin to learning a new language, so you might as well have the control of programming.&lt;/p&gt;
&lt;p&gt;Most enterprises have DBAs that learn these products inside out, and do little else. It&apos;s not fast, and it&apos;s not something anyone else in the organization can do. &lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet, when we&apos;ve often been asked to help large enterprises produce a modern API from a group of out-dated and disparate APIs, we can consistently out perform integration products in terms of development speed and quality because we have the ultimate middleware: Node.js.&lt;/p&gt;
&lt;p&gt;With Node.js as a middleware, we can easily poll or listen to events, gather data, do translations, and deliver data to the other side due to the evented structure of Node.js and the passionate community producing quality libraries on npm. &lt;/p&gt;
&lt;p&gt;With that, combined with the straight-forward scripting that JavaScript lends itself to, we can deliver a one-two punch to produce high quality middleware at speeds that never fail to surprise our clients.&lt;/p&gt;
&lt;p&gt;Yes, Node.js is nice for building realtime webapps, but that&apos;s just because it&apos;s modern, event driven, middleware-scripting with the ability to work with APIs and protocols directly; it can solve so many more problems that face enterprises just as elegantly as it can produce realtime web applications.&lt;/p&gt;
&lt;p&gt;Why learn a configuration tool or rely on a very narrow field of knowledge to bridge complicated interfaces? Just listen for events, look at data from each side, and script something together quickly.&lt;/p&gt;
&lt;p&gt;Now anyone in your organization that can write JavaScript can deploy and maintain your middleware solutions.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you&apos;d like assistance in enabling your company with modern development and IT practices &lt;a href=&quot;https://andyet.com/contact&quot;&gt;let us know!&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Creating a Document-Store Hybrid in Postgres 9.5]]></title><description><![CDATA[Document-Stores, Key-Stores, and Relational databases all have different use cases that they work best for, but there is quite a bit of…]]></description><link>https://blog.andyet.com/2016/02/04/postgres-9.5-document-store-hybrid/</link><guid isPermaLink="false">https://blog.andyet.com/2016/02/04/postgres-9.5-document-store-hybrid/</guid><pubDate>Thu, 04 Feb 2016 13:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/400417d49bc498e424cbc401bafdd04b/1cfc2/spreadsheet-with-filedrawer.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 41.72185430463576%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsSAAALEgHS3X78AAABVklEQVQY022P2WvCQBCH/f8f+2IKRfvSgz4V6oWg8S6pUhU19Yxn3COb3U1MtFbETrRioYVZ+Nj5fTO7ocPh8LXbef7aX29O5fkb78x/69Ta7/cghuDUB5Or5/RNuhjJlMMJVUmo0WwlgLh6m60oAWQBwnFo5SCjpPKUyx+51jOUWKY1HHeMaaM7rOuDzvgI3VF7vKjpo0Zvok/m73ofLtvGtNk3HHd1kaOpvOTcldK2mIWp5zgEkaL68lZ+0Ep33VbB4cIi1KYWZITNfW99kSPJHKUWYzZGxFwgzsVsZt4/PqmviYIWUytJYzJDiKAlhgwhluf5vzYn8xfZRMy2CabNRrvampaqw3JtNF2Aif6RtY/hdSzLLMZtDg4ykeACnk0xlUIQjAnCQoiliWE0ZCzKvNVZnhOm6QPHcV13JQT8XQTAJbcD4ABcHgEmSEhJ6Ww/tyB+A9wOp0vFb4MvAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;spreadsheet with file drawer&quot;
        title=&quot;&quot;
        src=&quot;/static/400417d49bc498e424cbc401bafdd04b/90cbd/spreadsheet-with-filedrawer.png&quot;
        srcset=&quot;/static/400417d49bc498e424cbc401bafdd04b/29fe9/spreadsheet-with-filedrawer.png 151w,
/static/400417d49bc498e424cbc401bafdd04b/6728c/spreadsheet-with-filedrawer.png 303w,
/static/400417d49bc498e424cbc401bafdd04b/90cbd/spreadsheet-with-filedrawer.png 605w,
/static/400417d49bc498e424cbc401bafdd04b/1cfc2/spreadsheet-with-filedrawer.png 900w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Document-Stores, Key-Stores, and Relational databases all have different use cases that they work best for, but there is quite a bit of overlap.
What if we were to have the advantages of all of these databases in one hybrid database?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://postgresql.org/&quot;&gt;Postgresql&lt;/a&gt; can store and query JSON, and now has a PUT/UPSERT equivalent with &lt;a href=&quot;http://www.postgresql.org/docs/current/static/sql-insert.html&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;INSERT ... ON CONFLICT ... DO UPDATE&lt;/code&gt;&lt;/a&gt; so we can easily use Postgresql as a Document-Store like &lt;a href=&quot;https://couchdb.apache.org/&quot;&gt;CouchDB&lt;/a&gt;
as well as being able to take advantage of normalized tables with the same data.&lt;/p&gt;
&lt;p&gt;In this blog post, I&apos;ll walk you through some postgres wizardry to treat 3rd party data in postgresql like a document-store and show you how to normalize parts of that data automatically.&lt;/p&gt;
&lt;h2 id=&quot;getting-the-data&quot;&gt;&lt;a href=&quot;#getting-the-data&quot; aria-label=&quot;getting the data permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Getting the Data&lt;/h2&gt;
&lt;p&gt;NASA has some pretty interesting data in &lt;a href=&quot;https://api.nasa.gov/api.html&quot;&gt;their APIs&lt;/a&gt; like information about &lt;a href=&quot;https://api.nasa.gov/api.html#NeoWS&quot;&gt;known asteroids near Earth&lt;/a&gt;, but I chose the boring API of &lt;a href=&quot;https://api.nasa.gov/api.html#patents&quot;&gt;Patents&lt;/a&gt; because it had some data to normalize, the &quot;innovators&quot; of a patent.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; -o data.json &lt;span class=&quot;token string&quot;&gt;&quot;https://api.nasa.gov/patents/content?limit=10000&amp;amp;api_key=DEMO_KEY&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If that&apos;s not working, get an API key from &lt;a href=&quot;https://api.nasa.gov/&quot;&gt;NASA&apos;s API site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At the top of the JSON file, I currently see a &lt;code class=&quot;language-text&quot;&gt;count&lt;/code&gt; value of &lt;code class=&quot;language-text&quot;&gt;1324&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1324&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;results&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;category&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;materials and coatings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;client_record_id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;patent_ARC-14661-3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;center&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ARC&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;eRelations&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;reference_number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ARC-14661-3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;expiration_date&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;abstract&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Method and system for functionalizing a collection ...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Selective functionalization of carbon nanotubes ...&quot;&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;innovator&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;lname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Khare&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;mname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;N.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;company&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SETI Institute&quot;&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;fname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bishun&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;lname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Meyyappan&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;company&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NASA Ames Research Center&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;order&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;fname&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Meyya&quot;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;contact&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;office&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Technology Partnerships Division&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;facility&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NASA Ames Research Center&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Trupti.D.Sanghani@nasa.gov&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Trupti D. Sanghani&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;address&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mail Stop 202A-3, Moffett Field, CA 94035&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;publication&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;concepts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fundamental physics concepts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Metric space&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Carbon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Temperature&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;5&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Carbon nanotube&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Gas&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;7&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Topology&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;6&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ionizing radiation&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;serial_number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;11/387,503&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;_id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;53f65b3d5904da2c9fc3008f&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;patent_number&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;7767270&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;patent_ARC-14661-3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;trl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;3 - Proof-of-concept&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DATABASE&lt;/span&gt; nasa_patents&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
\&lt;span class=&quot;token keyword&quot;&gt;connect&lt;/span&gt; nasa_patents&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; patents &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
	id &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; JSONB&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	created &lt;span class=&quot;token keyword&quot;&gt;TIMESTAMP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TIME&lt;/span&gt; ZONE &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	updated &lt;span class=&quot;token keyword&quot;&gt;TIMESTAMP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TIME&lt;/span&gt; ZONE &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In order to have the updated field work properly, we&apos;ll make a stored procedure for it and hook it up with a trigger.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; update_modified_column&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
    NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;updated &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;language&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;plpgsql&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; trigger_patents_updated BEFORE &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; patents
  &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PROCEDURE&lt;/span&gt; update_modified_column&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will set the &lt;code class=&quot;language-text&quot;&gt;updated&lt;/code&gt; column before the update is complete.&lt;/p&gt;
&lt;p&gt;Now let&apos;s load the data up. Of course, you don&apos;t have to use Node.js like I am here.
In your language of choice, insert into the &lt;code class=&quot;language-text&quot;&gt;patents&lt;/code&gt; TABLE for each entry of data.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&apos;use strict&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./data.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;pg-promise&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;postgres://localhost/nasa_patents&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; queries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; row &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    queries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;`INSERT INTO patents (id, data)
      VALUES ($1, $2)
      ON CONFLICT (id) DO UPDATE SET data=$2`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;batch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queries&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  pg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;done&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  pg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&apos;ve normalized &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt; from &lt;code class=&quot;language-text&quot;&gt;entry._id&lt;/code&gt; right off the bat. If there&apos;s any other data that you&apos;d like normalized in the table, feel free to alter your table and add it to your &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt;.
If you wanted to auto-generate &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;s instead, use the &lt;code class=&quot;language-text&quot;&gt;SERIAL&lt;/code&gt; type, or a UUID type with an extension.&lt;/p&gt;
&lt;p&gt;Notice the &lt;code class=&quot;language-text&quot;&gt;ON CONFLICT&lt;/code&gt; clause; this makes our &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt; more like a &lt;code class=&quot;language-text&quot;&gt;PUT&lt;/code&gt; in a document-store, and keeps our data in sync. We can run this as many times as we want and we&apos;ll only create as many rows as our &lt;code class=&quot;language-text&quot;&gt;data.results&lt;/code&gt; has &lt;code class=&quot;language-text&quot;&gt;entries&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If we wanted a &lt;code class=&quot;language-text&quot;&gt;MERGE&lt;/code&gt; behavior instead, meaning that we&apos;d &lt;code class=&quot;language-text&quot;&gt;DELETE&lt;/code&gt; database entries that aren&apos;t in &lt;em&gt;data.json&lt;/em&gt;, we&apos;d have to take a more complicated approach.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&apos;use strict&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./data.json&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;pg-promise&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;postgres://localhost/nasa_patents&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; queries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;DROP TABLE IF EXISTS _patents_incoming&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;`CREATE TABLE _patents_incoming (
      id TEXT PRIMARY KEY NOT NULL, data JSONB
    )`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; entry &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    queries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;`INSERT INTO _patents_incoming (id, data)
      VALUES ($1, $2)`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  queries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;tx2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; queries2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;`DELETE FROM patents USING patents AS p1
        LEFT OUTER JOIN _patents_incoming AS p2 ON p1.id=p2.id
        WHERE patents.id=p1.id AND p2.id IS NULL`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;`INSERT INTO patents SELECT * FROM _patents_incoming
        ON CONFLICT (id) DO UPDATE SET data=(
        SELECT data FROM _patents_incoming WHERE id=patents.id)`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; tx2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;batch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queries2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; tx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;batch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;queries&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  pg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;done&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  pg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case, we &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt; the data into a temporary table.
We can then &lt;code class=&quot;language-text&quot;&gt;LEFT OUTER JOIN&lt;/code&gt; from the patents table to our temporary table, deleting any rows where we don&apos;t have matching data.
From there, we &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt; using a &lt;code class=&quot;language-text&quot;&gt;SELECT&lt;/code&gt; of our temporary table, replacing the data when the ids conflict.&lt;/p&gt;
&lt;p&gt;We could make a stored procedure to do this more cleanly, but we&apos;d have to guarantee our JSON parameter we were passing it was less than 1GB.
In fact, in the case of big files, we&apos;d want to load this file asynchronously, parsing the JSON as we go and inserting it, but that&apos;s a bit out of scope for this blog post.
If you have a better way of doing a &lt;code class=&quot;language-text&quot;&gt;MERGE&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;DELETE&lt;/code&gt; with a large JSON array, I&apos;d love to see it.&lt;/p&gt;
&lt;h2 id=&quot;simple-get-and-put-procedures&quot;&gt;&lt;a href=&quot;#simple-get-and-put-procedures&quot; aria-label=&quot;simple get and put procedures permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Simple Get and Put Procedures&lt;/h2&gt;
&lt;p&gt;These are pretty simple, and maybe not worth doing, but it&apos;s a key/document-store right, so we must have Get and Put functions!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; GetPatent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;in_id &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; SETOF patents &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$ &lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; QUERY &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; patents &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;in_id &lt;span class=&quot;token keyword&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;language&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;plpgsql&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;category&apos;&lt;/span&gt; category
  &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; getpatent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;53f656f85904da2c9fc2fe6b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;--aeronautics&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; PutPatent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;in_data JSON&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;DECLARE&lt;/span&gt;
	r_id &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; patents &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;in_data::JSONB&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;_id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      in_data::JSONB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; CONFLICT &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DO&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;in_data::JSONB RETURNING id
      &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; r_id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; r_id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;language&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;plpgsql&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; PutPatent&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;{&quot;_id&quot;: &quot;ham&quot;, &quot;test&quot;: &quot;value&quot;}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;-- ham&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A fun note here, if you run the &lt;code class=&quot;language-text&quot;&gt;MERGE&lt;/code&gt; Node.js after this, it should get rid of your &quot;ham&quot; entry because it &lt;code class=&quot;language-text&quot;&gt;DELETE&lt;/code&gt;s any entries in new data.&lt;/p&gt;
&lt;h2 id=&quot;the-hybrid-part&quot;&gt;&lt;a href=&quot;#the-hybrid-part&quot; aria-label=&quot;the hybrid part permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Hybrid Part&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;But so far, this is just a really basic document-store; I thought you said hybrid?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Oh, right, sorry about that.
You may noticed that we&apos;re normalizing &lt;code class=&quot;language-text&quot;&gt;data-&amp;gt;&amp;gt;&amp;#39;_id&amp;#39;&lt;/code&gt; out to &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt; when &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt;ing.
We could make that a bit more transparent with a trigger, so let&apos;s add one for &lt;code class=&quot;language-text&quot;&gt;category&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;ALTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; patents &lt;span class=&quot;token keyword&quot;&gt;ADD&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;COLUMN&lt;/span&gt; category &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; normalize_patents_category&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
	NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;category :&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;category&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;language&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;plpgsql&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; trigger_patents_normalize_category
  BEFORE &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; patents &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PROCEDURE&lt;/span&gt; normalize_patents_category&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now you can re-run your merge or import scripts, and you&apos;ll have your category data expanded out.
But this isn&apos;t very useful, is it? I mean, that data wasn&apos;t hard to deal with anyway.
Let&apos;s do something more interesting.&lt;/p&gt;
&lt;h2 id=&quot;something-more-interesting&quot;&gt;&lt;a href=&quot;#something-more-interesting&quot; aria-label=&quot;something more interesting permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Something More Interesting&lt;/h2&gt;
&lt;p&gt;In each patent is a list of innovators.
Let&apos;s break them out into their own table, and keep it in sync.
It&apos;s likely that some innovators may have more than one patent, so let&apos;s make a trigger that keeps a list of unique patent innovators.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; innovators &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
	fname &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	lname &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	mname &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	company &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;CONSTRAINT&lt;/span&gt; innovators_pkey
      &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; company&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; patents_to_innovators&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;DECLARE&lt;/span&gt;
	nr innovators&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;rowtype&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;FOR&lt;/span&gt; nr &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;jsonb_populate_recordset&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;null&lt;/span&gt;::innovators&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;innovator&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;LOOP&lt;/span&gt;
		nr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fname :&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;COALESCE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		nr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lname :&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;COALESCE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		nr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mname :&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;COALESCE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		nr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;company :&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;COALESCE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;company&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; innovators &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; company&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; nr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; CONFLICT &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CONSTRAINT&lt;/span&gt; innovators_pkey &lt;span class=&quot;token keyword&quot;&gt;DO&lt;/span&gt; NOTHING&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;LOOP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;LANGUAGE&lt;/span&gt; plpgsql&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; trigger_patents_to_innovators
  &lt;span class=&quot;token keyword&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; patents
  &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PROCEDURE&lt;/span&gt; patents_to_innovators&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if you run your merge or import script, it&apos;ll populate the list of unique names.
You may notice that all of the &lt;code class=&quot;language-text&quot;&gt;NEW.data-&amp;gt;&amp;#39;innovator&amp;#39;&lt;/code&gt; fields are &lt;code class=&quot;language-text&quot;&gt;COALESCE&lt;/code&gt;d with empty strings to prevent &lt;code class=&quot;language-text&quot;&gt;NULL&lt;/code&gt; values.
You might think &lt;code class=&quot;language-text&quot;&gt;NULL&lt;/code&gt;s wouldn&apos;t cause a problem (I thought that too), but in Postgresql &lt;code class=&quot;language-text&quot;&gt;NULL = NULL&lt;/code&gt; is &lt;em&gt;never&lt;/em&gt; true, so the &lt;code class=&quot;language-text&quot;&gt;CONFLICT&lt;/code&gt; won&apos;t happen on or against rows with &lt;code class=&quot;language-text&quot;&gt;NULL&lt;/code&gt; and so we&apos;d get duplicate entries.
I &lt;code class=&quot;language-text&quot;&gt;COALESCE&lt;/code&gt; in the the &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt;&apos;s &lt;code class=&quot;language-text&quot;&gt;SELECT&lt;/code&gt;, but for the purpose of a blog post, showing it separately is more readable.&lt;/p&gt;
&lt;p&gt;So now we have nice, normalized data for innovators.
We could maybe make a SERIAL id for our primary key, and make a join table that references patents if we wanted to.&lt;/p&gt;
&lt;h2 id=&quot;another-use-case&quot;&gt;&lt;a href=&quot;#another-use-case&quot; aria-label=&quot;another use case permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Another Use Case&lt;/h2&gt;
&lt;p&gt;The scenario that inspired this post was a 3rd party JSON feed of objects, each with child ids that refer to root level objects.
In essence I had a flat array of objects, like our first example, but another view of the data was that of a tree.&lt;/p&gt;
&lt;p&gt;Making a dependency flattened dependence tree for a specific object was straight forward with a &lt;a href=&quot;http://www.postgresql.org/docs/current/static/queries-with.html&quot;&gt;CTE&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; RECURSIVE dtree&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; objects &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;some_id&apos;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;-- specify the object to start with&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;UNION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ALL&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; modules&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; modules&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; modules
  &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; dtree &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;dtree&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; dtree&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But going the other direction, finding all of the objects that have a direct or indirect requirement of a specific object id in their dependency tree was harder.
My first attempt at this involved a query that expanded out each object&apos;s dependency tree as above, and looked for instances of the object in question in that tree.
This proved to be way too slow; I needed to normalize the data.&lt;/p&gt;
&lt;p&gt;You&apos;ll notice it looks similar to how we normalized innovators.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; dependencies &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  id &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SERIAL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  object_id &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  sub_dependency_id &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;CONSTRAINT&lt;/span&gt; dependencies_dupes
    &lt;span class=&quot;token keyword&quot;&gt;UNIQUE&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;object_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sub_dependency_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; objects_to_dependencies&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;DECLARE&lt;/span&gt;
	nr dependencies&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;ROWTYPE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;FOR&lt;/span&gt; object_cte &lt;span class=&quot;token operator&quot;&gt;IN&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; jsonb_array_elements_text&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;dependencies&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; sub_dependency_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; object_id
	&lt;span class=&quot;token keyword&quot;&gt;LOOP&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; depenedencies &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;object_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sub_dependency_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; object_cte&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; CONFLICT &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;CONSTRAINT&lt;/span&gt; dependencies_dupes &lt;span class=&quot;token keyword&quot;&gt;DO&lt;/span&gt; NOTHING&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;LOOP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;LANGUAGE&lt;/span&gt; plpgsql&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; trigger_patents_to_innovators
  &lt;span class=&quot;token keyword&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; patents
  &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PROCEDURE&lt;/span&gt; patents_to_innovators&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that all of the data is normalized (at least the next time I sync, which I can do manually with an empty update), I can go reverse through the tree to find which objects use another object somewhere in their dependency tree.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; RECURSIVE  dtree&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;object_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sub_dependency_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; dependencies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;object_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; objects&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    dependencies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sub_depedency_id
    &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; dependencies
    &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; objects &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;dependencies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;object_id
    &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; dependencies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sub_dependency_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;some_id&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;UNION&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ALL&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; objects&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;object_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; objects&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    dependencies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sub_dependency_id &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; dependency
    &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; dependencies &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; dtree parent
      &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; parent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;object_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;dependencies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sub_dependency_id
    &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; object &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;object_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;dependencies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;object_id
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; object_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; dependencies&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This runs quite a bit faster than having to expand out the dependency tree of every object and check for the existence of the object I&apos;m searching for as a dependency.&lt;/p&gt;
&lt;h2 id=&quot;bonus-example&quot;&gt;&lt;a href=&quot;#bonus-example&quot; aria-label=&quot;bonus example permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bonus Example&lt;/h2&gt;
&lt;p&gt;Since we&apos;re using Postgresql as a document-store and relational database hybrid, we can do cool things, like joining two documents to each other.
This was rather difficult in Postgresql 9.4, as there wasn&apos;t a way to modify a JSON(B) value in place.
Now we can add fields and remove fields with the operators added in 9.5.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; authors &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; JSONB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; books &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; JSONB&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; author_id
  &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; authors &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; authors &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;first_name&quot;: &quot;Mike&quot;, &quot;last_name&quot;: &quot;Speegle&quot;,
  &quot;dob&quot;: &quot;1979-02-03&quot;}&apos;&lt;/span&gt;::JSONB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;first_name&quot;: &quot;Patrick&quot;, &quot;last_name&quot;: &quot;Rothfuss&quot;,
  &quot;dob&quot;: &quot;1973-06-06&quot;}&apos;&lt;/span&gt;::JSONB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; books &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; author_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;title&quot;: &quot;The Name of the Wind&quot;,
  &quot;ISBN&quot;: &quot;978-0-7564-0407-9&quot;}&apos;&lt;/span&gt;::JSONB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;title&quot;: &quot;Wise Man&apos;&apos;s Fear&quot;,
  &quot;ISBN&quot;: &quot;978-0-7564-0473-4&quot;}&apos;&lt;/span&gt;::JSONB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;title&quot;: &quot;Something Greater Than Artifice&quot;,
  &quot;ISBN&quot;: &quot;978-0-692-26050-0&quot;}&apos;&lt;/span&gt;::JSONB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;title&quot;: &quot;Pen and Platen: Short Stories Written the Long Way&quot;,
  &quot;ISBN&quot;: &quot;978-0615574165&quot;}&apos;&lt;/span&gt;::JSONB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{&quot;title&quot;: &quot;A Slow Regard of Silent Things&quot;,
  &quot;ISBN&quot;: &quot;978-0-7564-1043-8&quot;}&apos;&lt;/span&gt;::JSONB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token keyword&quot;&gt;WITH&lt;/span&gt; author_books_cte &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
 	&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; authors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; author_data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; json_agg&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;books&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; books_data
 		&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; authors
 		&lt;span class=&quot;token keyword&quot;&gt;LEFT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;JOIN&lt;/span&gt; books &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; books&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;author_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;authors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id &lt;span class=&quot;token keyword&quot;&gt;GROUP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BY&lt;/span&gt; authors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id
 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; jsonb_pretty&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;author_data &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; jsonb_build_object&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;books&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; books_data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; authors
 	&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; author_books_cte&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;                                  authors
---------------------------------------------------------------------
 {                                                                  
     &amp;quot;dob&amp;quot;: &amp;quot;1979-02-03&amp;quot;,                                           
     &amp;quot;books&amp;quot;: [                                                     
         {                                                          
             &amp;quot;ISBN&amp;quot;: &amp;quot;978-0-692-26050-0&amp;quot;,                           
             &amp;quot;title&amp;quot;: &amp;quot;Something Greater Than Artifice&amp;quot;             
         },                                                         
         {                                                          
             &amp;quot;ISBN&amp;quot;: &amp;quot;978-0615574165&amp;quot;,                              
             &amp;quot;title&amp;quot;: &amp;quot;Pen and Platen: Short Stories Written the
                Long Way&amp;quot;
         }                                                          
     ],                                                             
     &amp;quot;last_name&amp;quot;: &amp;quot;Speegle&amp;quot;,                                        
     &amp;quot;first_name&amp;quot;: &amp;quot;Mike&amp;quot;                                           
 }
 {                                                                  
     &amp;quot;dob&amp;quot;: &amp;quot;1973-06-06&amp;quot;,                                           
     &amp;quot;books&amp;quot;: [                                                     
         {                                                          
             &amp;quot;ISBN&amp;quot;: &amp;quot;978-0-7564-0407-9&amp;quot;,                           
             &amp;quot;title&amp;quot;: &amp;quot;The Name of the Wind&amp;quot;                        
         },                                                     
         {                                                      
             &amp;quot;ISBN&amp;quot;: &amp;quot;978-0-7564-0473-4&amp;quot;,                       
             &amp;quot;title&amp;quot;: &amp;quot;Wise Man&amp;#39;s Fear&amp;quot;                         
         },                                                 
         {                                                      
             &amp;quot;ISBN&amp;quot;: &amp;quot;978-0-7564-1043-8&amp;quot;,                       
             &amp;quot;title&amp;quot;: &amp;quot;A Slow Regard of Silent Things&amp;quot;          
         }                                                      
     ],                                                         
     &amp;quot;last_name&amp;quot;: &amp;quot;Rothfuss&amp;quot;,                               
     &amp;quot;first_name&amp;quot;: &amp;quot;Patrick&amp;quot;                                
 }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By joining and aggregating the data with a &lt;code class=&quot;language-text&quot;&gt;JOIN&lt;/code&gt; in a &lt;code class=&quot;language-text&quot;&gt;CTE&lt;/code&gt; and then building the joined object with a &lt;code class=&quot;language-text&quot;&gt;CONCAT&lt;/code&gt; operator (new in 9.5), I can place the book data inside the authors data.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you have any thoughts, questions, or suggestions on improving these queries, please &lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;Tweet me @fritzy&lt;/a&gt;.
If you&apos;d like some help working with your data in this way, please &lt;a href=&quot;https://andyet.com/contact/&quot;&gt;contact us&lt;/a&gt;.
Maybe it&apos;s time for you to &lt;a href=&quot;http://cryto.net/~joepie91/blog/2015/07/19/why-you-should-never-ever-ever-use-mongodb/&quot;&gt;migrate away from MongoDB&lt;/a&gt;?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Simplifying Docker on OS X]]></title><description><![CDATA[Docker is an amazing product. In a very short amount of time it's drastically changed (for the better) how we at &yet deploy our…]]></description><link>https://blog.andyet.com/2016/01/25/easy-docker-on-osx/</link><guid isPermaLink="false">https://blog.andyet.com/2016/01/25/easy-docker-on-osx/</guid><pubDate>Mon, 25 Jan 2016 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d3e12fcb09ef5313df91716c6c8aa604/146da/docker_and_osx.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 41.72185430463576%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsSAAALEgHS3X78AAABOklEQVQY03VRvUoDQRC+wjew9hUsfQFfwtewSWcZsLARhFRaaK0EC0GjGKuggmBQBA1BAvECuWDuZmd2Z3/d5C6CqB8DOzDfNz/fJmIBWED8g9+EpHyKAphVCJ6ZiWhGFTMWLGREaIyOoSR962fiAsAaHeuH7dvO23sIAYVARCbUEiNVxn7aofHaemDHSpX6pKxlgBv7zeXa7lbz6ryX1i67WuTP6aQ7HCsUWmsfQprTcCLYBu9sNTkH4Qk2j6+T+slKo7W0fbrWOLt4fAlMe/e9nc6rk6S1ievAaDTu92PinKvEcXK88mnwUW/drR60149uHgajYHW8NJsWMaIBknWQaMep+8z8NDPOV2uXfmjm4K0iLBuXhiAKQpznyJK8c3F5o2S046fbAIUQSkkQmBd//BbMLcSqV4UvR4S4u4ub9GUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Docker and OS X&quot;
        title=&quot;&quot;
        src=&quot;/static/d3e12fcb09ef5313df91716c6c8aa604/90cbd/docker_and_osx.png&quot;
        srcset=&quot;/static/d3e12fcb09ef5313df91716c6c8aa604/29fe9/docker_and_osx.png 151w,
/static/d3e12fcb09ef5313df91716c6c8aa604/6728c/docker_and_osx.png 303w,
/static/d3e12fcb09ef5313df91716c6c8aa604/90cbd/docker_and_osx.png 605w,
/static/d3e12fcb09ef5313df91716c6c8aa604/a2b88/docker_and_osx.png 908w,
/static/d3e12fcb09ef5313df91716c6c8aa604/146da/docker_and_osx.png 943w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.docker.com&quot;&gt;Docker&lt;/a&gt; is an amazing product. In a very short amount of time it&apos;s drastically changed (for the better) how we at &lt;a href=&quot;https://andyet.com&quot;&gt;&amp;#x26;yet&lt;/a&gt; deploy our applications. With everything containerized, it becomes very easy to run an arbitrary number of apps on a small cluster of servers.&lt;/p&gt;
&lt;p&gt;However, there&apos;s one big challenge with adopting Docker for our developers: it doesn&apos;t natively work on OS X.&lt;/p&gt;
&lt;p&gt;There have been several solutions for this, such as &lt;a href=&quot;http://boot2docker.io&quot;&gt;boot2docker&lt;/a&gt; and &lt;a href=&quot;https://docs.docker.com/machine/&quot;&gt;docker-machine&lt;/a&gt;. These tools create and manage a virtual machine for you that runs the Docker daemon. This allows you to configure the Docker client to communicate with the virtual machine, effectively allowing you to use containers in OS X.&lt;/p&gt;
&lt;p&gt;These existing tools work well, but I felt like they were too complex. Why do I need to run &lt;code class=&quot;language-text&quot;&gt;eval $(docker-machine env docker)&lt;/code&gt; just so I can work? I just want to use Docker, I don&apos;t want to have to remember to run a command and pay attention to environment variables just to build a container.&lt;/p&gt;
&lt;p&gt;The reason those environment variables are necessary is because the Docker client defaults to sending requests to &lt;code class=&quot;language-text&quot;&gt;/var/run/docker.sock&lt;/code&gt;, which is a unix socket file that exists on a computer that&apos;s running the Docker daemon. Since the Docker daemon is actually running in a virtual machine, that file doesn&apos;t exist in OS X so we have to tell the client what to connect to by setting environment variables.&lt;/p&gt;
&lt;p&gt;But what if we could just make that socket file exist? That would remove the need for setting environment variables. This means no more running &lt;code class=&quot;language-text&quot;&gt;eval&lt;/code&gt; commands in your bash profile, something that has always made the Ops part of me very nervous.&lt;/p&gt;
&lt;p&gt;That idea was the inspiration behind my project &lt;a href=&quot;https://github.com/nlf/dlite&quot;&gt;DLite&lt;/a&gt;. I wrote DLite in Go, which allows me to distribute it as a single binary, which is incredibly user friendly. Installation is as simple as downloading &lt;a href=&quot;https://github.com/nlf/dlite/releases&quot;&gt;the binary&lt;/a&gt; for the latest release, copying it somewhere in your &lt;code class=&quot;language-text&quot;&gt;PATH&lt;/code&gt; (homebrew users, the easiest place is &lt;code class=&quot;language-text&quot;&gt;/usr/local/bin/&lt;/code&gt;) and running &lt;code class=&quot;language-text&quot;&gt;sudo dlite install&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The installation script creates an empty file to serve as your virtual machine&apos;s hard drive, and downloads an operating system that the virtual machine will run. Currently the operating system in use is &lt;a href=&quot;https://github.com/nlf/dhyve-os&quot;&gt;DhyveOS&lt;/a&gt; another of my projects that was created with the intention of giving you the smallest possible OS to allow running Docker.&lt;/p&gt;
&lt;p&gt;After the installation, you can start the virtual machine by running &lt;code class=&quot;language-text&quot;&gt;launchctl start local.dlite&lt;/code&gt;. You could also log out and log back in to have it started for you automatically. Since DLite leverages a per-user launchd agent, it will run as soon as you log in. After waiting a few seconds (the virtual machine needs a short amount of time to boot) and installing the Docker client if you haven&apos;t already (I recommend homebrew for that, &lt;code class=&quot;language-text&quot;&gt;brew install docker&lt;/code&gt;), you can start running Docker commands.&lt;/p&gt;
&lt;p&gt;Since DLite creates a &lt;code class=&quot;language-text&quot;&gt;/var/run/docker.sock&lt;/code&gt; file that simply forwards requests to the correct port of the virtual machine, there is no additional setup. There&apos;s no need to set any environment variables, or to &lt;code class=&quot;language-text&quot;&gt;eval&lt;/code&gt; some strange looking command. The Docker client just works.&lt;/p&gt;
&lt;p&gt;Since mounting volumes into a container is one of Docker&apos;s big strengths, DLite also mounts your entire &lt;code class=&quot;language-text&quot;&gt;/Users&lt;/code&gt; directory into the virtual machine via NFS. This means that for most use cases, you&apos;ll be able to attach your volumes without issue.&lt;/p&gt;
&lt;p&gt;Since Docker is, in fact, running in a virtual machine the only other thing you have to get used to is that your services aren&apos;t available at &lt;code class=&quot;language-text&quot;&gt;localhost&lt;/code&gt;. Instead DLite creates an entry in your &lt;code class=&quot;language-text&quot;&gt;/etc/hosts&lt;/code&gt; file for you so you can access your services at the hostname &lt;code class=&quot;language-text&quot;&gt;local.docker&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As part of the installation, DLite also injects your public SSH key into the virtual machine. If you needed to access the virtual machine directly for some reason, that can be done by running &lt;code class=&quot;language-text&quot;&gt;ssh docker@local.docker&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now for the bad news. DLite leverages &lt;a href=&quot;https://github.com/mist64/xhyve&quot;&gt;xhyve&lt;/a&gt; through some &lt;a href=&quot;https://github.com/TheNewNormal/libxhyve&quot;&gt;Go bindings&lt;/a&gt;. This means that all of xhyve&apos;s limitations also apply to DLite. You need to be on at least OS X Yosemite (specifically 10.10.3) and have a relatively new Mac in order to use it.&lt;/p&gt;
&lt;p&gt;If you meet xhyve&apos;s requirements, however, I think DLite is about as easy as Docker on OS X can get.&lt;/p&gt;
&lt;p&gt;Try it out, let me know what you think. If you have any problems don&apos;t hesitate to open an &lt;a href=&quot;https://github.com/nlf/dlite/issues&quot;&gt;issue&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[UX and WebRTC blog series]]></title><description><![CDATA[At the end of 2015, we teamed up with AT&T to write a blog series on UX and WebRTC. We’re excited about the future of communication on the…]]></description><link>https://blog.andyet.com/2016/01/21/att-webrtc-ux-series/</link><guid isPermaLink="false">https://blog.andyet.com/2016/01/21/att-webrtc-ux-series/</guid><pubDate>Thu, 21 Jan 2016 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At the end of 2015, we teamed up with AT&amp;#x26;T to write a blog series on UX and WebRTC. We’re excited about the future of communication on the web and hope these posts will help teams get started in creating enjoyable user experiences with WebRTC. Check them out!&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/85f8f25a5d1219ee7b04dc597aad70ec/5a190/webrtc-ux-series-1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 39.735099337748345%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsSAAALEgHS3X78AAABbUlEQVQY04VQ2U7CQBTlW/0NY4wPRhNMlIgRsULkASPU+AQYl2BYyyKLlLaUUoZFtk5nKdEHCOIUjA/64M2ZzLknczP3HAc0kcEOoYPhSMwL3U4XEwtCk2n/wmFPItTtDx9P9lNbG3HXtg46hkmYPjHgHxjjibHm7IEDIbNQ0y9CCf5oL3/pevI4y/FjoCYMSCm1CLUwoWgFxqk1XYOJ9vBkPApEatEMWCxms8Xn9GMOteux5JYVtVgsFQpFRVGrr7V6XRKEXCKRZEhnsqVyxV4bYxR5rvDR3HJV8/kylb1USgGtBbzec7u83JnH6/P5OY4LhcKx2B0f5pOp9GptOtXESunKCccjUa4mXx78kcN0MUnpe1PT2m3QUJtiXZIkWWvprO2/DdgtKw37Z2jifr8n3xyIwV3f6abrdid479aBjjAxMTYRZoQZtp3bCrHzxeTbswEhRKQLgF4Veh1QlSqtto4QWee5xk+8v9ovxeqZlkw9WmMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;WebRTC and UX&quot;
        title=&quot;&quot;
        src=&quot;/static/85f8f25a5d1219ee7b04dc597aad70ec/90cbd/webrtc-ux-series-1.png&quot;
        srcset=&quot;/static/85f8f25a5d1219ee7b04dc597aad70ec/29fe9/webrtc-ux-series-1.png 151w,
/static/85f8f25a5d1219ee7b04dc597aad70ec/6728c/webrtc-ux-series-1.png 303w,
/static/85f8f25a5d1219ee7b04dc597aad70ec/90cbd/webrtc-ux-series-1.png 605w,
/static/85f8f25a5d1219ee7b04dc597aad70ec/5a190/webrtc-ux-series-1.png 800w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt; &lt;br /&gt;&lt;strong&gt;&lt;a href=&quot;http://developerboards.att.lithium.com/t5/AT-T-Developer-Program-Blogs/6-Key-UX-elements-to-consider-when-getting-started-with-WebRTC/ba-p/40823&quot;&gt;Post #1: Getting started with UX and WebRTC&lt;/a&gt;&lt;/strong&gt; &lt;br /&gt;An introduction to WebRTC featuring reasons to include it in your application, a handful of questions to consider during the initial stages of planning, and the importance of consistency and seamless implementation. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8cfea4376116eba7b7b060d49f5346aa/5a190/webrtc-ux-series-2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 56.29139072847682%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACLElEQVQoz01SW28SQRjdn2figy8aI8bESzHqQ/HFxktMm5pGE6NtY62CDdASS6FSEUqwwCpske2iLJelLAJDKZRll53ZC5eavjkU2pCch8n3zZnvzDkfIUOE0YZQUztsgfsUcs96lkkm3u8dy0gZdiFSWqK0X+CFlogUdVjEIM6Y+i7LrATdiUzKtxtOJJlKBZQroC1DDE3TC3wxSsWbLbEptCRcOn2XGPRUvQBK7/yOWr1x0j/pd/rZbM7n83McV28caZ1erSUe1htdVQUAfCd/FMEBHE1GCErQGfO//GqmGDpb4hPpP+VyJZGgWTYtiFINVFnb0s6zSZdpwvfUFJ9/wUWCh0cCQgrR6fYiYXKbDK0FPbPWhRnLm2nb2718WkGqoqipLLdh/kAaL382XLRMGNZuXfEaLkSm7olSGysn+sf/1p0u8BdEmPjD18+3A4E58/yK16kqGn43GqMCwZ0MGbLcuORx2D0Lr+wPbmZoWoZwIFvvdGmGsdtWrd+ci8FVPHbO9d5NBbArqqbzfNHhdHsty4knxq3717buXqVmTEJTkJE6chu732wI7mhgkVz/GNtc+rlhDX+RMBvbAZGoaEnv5q/J6+xjY2rqNvXoDnYBqZosw9OoZIiHgOoBh6Mslfb5Ig5mlL8MFVWr1xv5XK7EF/l8Hh+GHx5NHl7C+iugik3OZHKYcL4JQz5OOPk7Re8l8ebAs+Uhxi9h/VjCOPMcg56mY4wX/wPUhBjjjG93BgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;WebRTC and UX&quot;
        title=&quot;&quot;
        src=&quot;/static/8cfea4376116eba7b7b060d49f5346aa/90cbd/webrtc-ux-series-2.png&quot;
        srcset=&quot;/static/8cfea4376116eba7b7b060d49f5346aa/29fe9/webrtc-ux-series-2.png 151w,
/static/8cfea4376116eba7b7b060d49f5346aa/6728c/webrtc-ux-series-2.png 303w,
/static/8cfea4376116eba7b7b060d49f5346aa/90cbd/webrtc-ux-series-2.png 605w,
/static/8cfea4376116eba7b7b060d49f5346aa/5a190/webrtc-ux-series-2.png 800w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt; &lt;br /&gt;&lt;strong&gt;&lt;a href=&quot;http://developerboards.att.lithium.com/t5/AT-T-Developer-Program-Blogs/3-Essential-UX-considerations-when-initiating-or-joining-a-call/ba-p/40873&quot;&gt;Post #2: UX considerations for initiating and joining calls&lt;/a&gt;&lt;/strong&gt; &lt;br /&gt;The first major interaction a user will have with WebRTC is initiating or joining a call. This post covers questions to ask and decisions to consider when designing this part of the flow. How do things like buttons, text, and user expectations affect the experience? &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/593903e0569b6ca0a94e3f5b8a30e169/9a86a/webrtc-ux-series-3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 57.6158940397351%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsSAAALEgHS3X78AAAC0UlEQVQozyVQ+08SAQDmT2rpNBNdrh9aU8rlI83pKp3llptGQ6PlM81MySeKzgcovkAhOZH0JANOj8fxOrhDjrvjjqfxEJf9Htq3b/u2b/v27fs40Vg84PcRZICimQBJUVlhWOYGbBah0DXZ0LUZZIM0Q9NZP/w7kUwkUxwv6gE2FgAQgM0WoxHSG2Ez4vZRYYxkXRhhR3EE9TgxD04RviDpZykfHbC5HEQgkL7IcIIMqz/8Lu5sWRrp0kMngIXeAO0fv0x1DU/LdWbAElQewwbSNrslbfvQ2fGpZ1wqOcJgPOBPpzMcmqYdCLg61gvIJyGrRWU6q3venJebl5+XX1v/Ysfo27d7F3fXiovvVZeX1VeXF9zhSpQyOhJKJdMckiJxnwUEdwxGjdXllu7BPB6v5ml1ZUUlt5ArWtg2kZFu0WBzfZVGNqhaGnjVUNXR38XEI8lsOBaLo6jHBEFBJkhFEn2i+eWZUbthzwXtD/YKa+oaV3WgZHNxSNgiHuJPfub38V8KB7qp/83Zt3Ect9mQv1dXZitSWFiklIkptzFBIcqV2ZxbOd+Wlua25XPDfMP2KLw7PvS+uWd8hD2/aQ5H41sqQHv4EyPObE70Nb9btblCO/RRDNpeX+4cFO8j6JR8/slj3szwu4mB9jJe6axCRoXZVCrNicTOZetShUrhwNyon9LaI6pT5scBCGrVWwbiwJ3QIqhEtVqSXzjb0zotaKoouCuSSoKx8M3m+PnC3Oi6XEIxtJdglUcWtWbBBh87TBqFckL9y6l14JPir1XcIkAkAMcEXQ9KKuqeYZjnInPJYUIh45EKgQ8uMxmnlzhYazhT59o17cjuG9/O7RN1o2wHWG+sFDx62P+2VdDWuthUKyy97z2FLv5cZQ+LMWyEDUUj0diZn8CdhyR2jDt1uEtH4r8Irx5BbJjJgJ+abFYrBFt8FjhghqLRaDKV/geoNPh7dHfmQAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;WebRTC and UX&quot;
        title=&quot;&quot;
        src=&quot;/static/593903e0569b6ca0a94e3f5b8a30e169/90cbd/webrtc-ux-series-3.png&quot;
        srcset=&quot;/static/593903e0569b6ca0a94e3f5b8a30e169/29fe9/webrtc-ux-series-3.png 151w,
/static/593903e0569b6ca0a94e3f5b8a30e169/6728c/webrtc-ux-series-3.png 303w,
/static/593903e0569b6ca0a94e3f5b8a30e169/90cbd/webrtc-ux-series-3.png 605w,
/static/593903e0569b6ca0a94e3f5b8a30e169/9a86a/webrtc-ux-series-3.png 792w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt; &lt;br /&gt;&lt;strong&gt;&lt;a href=&quot;http://developerboards.att.lithium.com/t5/AT-T-Developer-Program-Blogs/WebRTC-series-4-Indispensable-UX-patterns-to-create-transparent/ba-p/40898&quot;&gt;Post #3: UX patterns for transparent voice and video calls&lt;/a&gt;&lt;/strong&gt; &lt;br /&gt;Next, here are some useful patterns and techniques for the voice or video call itself. What information or context could help the user during the call? The theme here is clarity and transparency.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a7f5812aebf4452c73583c97ce3874b4/5a190/webrtc-ux-series-4.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 45.6953642384106%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAAsSAAALEgHS3X78AAAB3klEQVQozy1RTW/TQBD1j+LEjWMv3BB3boBA4kCRWhCKiFoVqaUCqsgS1AJSyoeq0OAmqKFFEYEoiZs4dhM7642b2Ampd23vOi09cGJcdzVa7czOm4/3BD8IwagfgCXvcwPXp0EcCRl3R+O8XERWP4qmv77ly/IWITQImZBgOBzG6UUV32enPv/nB5yCz/iqlLl/4/ryUqqw+z376Nb63M1SuRoyJkDp8Z9JRTlsaCakQiMaTIfmvq1kRi4O2cnYO05vvtgRH4vraamwW5C3tuXclx8HxPMESmmlheaXMqmVV81O3yMBNpV3yzNvFy4Vs7cnx95k4pUOKi/XnojvRWnj46dcblPe1ns4jMcmZK/eefYm/zxb/Nk0MB4YWnn14ZWns5dzmauOY5sIcxa5FpYe3EvNz6YXF/tHA9gStoaxmT10v+7XdsqNgTNinHuUm0rW2LuDtAKsAAwE0dQ2uuK1mW7pszR3t/G7Gp2cEurHhAGeMc4YDMIgFEf4GQnPAv4XyIMOcIfRVNl4nV9bqH6QwE+ojcEAaKltvdP1CE1qIcuq1euO48IbfkGtHrJqql5va9WmapiInGcKicL6YccwexdtQ3Y0GDZbKsgLKiZgZGFVbdt9W9d0hHCS+R8LIrxCQ/o0bAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;WebRTC and UX&quot;
        title=&quot;&quot;
        src=&quot;/static/a7f5812aebf4452c73583c97ce3874b4/90cbd/webrtc-ux-series-4.png&quot;
        srcset=&quot;/static/a7f5812aebf4452c73583c97ce3874b4/29fe9/webrtc-ux-series-4.png 151w,
/static/a7f5812aebf4452c73583c97ce3874b4/6728c/webrtc-ux-series-4.png 303w,
/static/a7f5812aebf4452c73583c97ce3874b4/90cbd/webrtc-ux-series-4.png 605w,
/static/a7f5812aebf4452c73583c97ce3874b4/5a190/webrtc-ux-series-4.png 800w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt; &lt;br /&gt;&lt;strong&gt;&lt;a href=&quot;http://developerboards.att.lithium.com/t5/AT-T-Developer-Program-Blogs/WebRTC-series-5-Crucial-ways-connectivity-and-bandwidth-affect/ba-p/40922&quot;&gt;Post #4: Ways connectivity and bandwidth affect WebRTC UX&lt;/a&gt;&lt;/strong&gt; &lt;br /&gt;A major part of the WebRTC experience is call quality, affected most by connectivity and bandwidth. In this post, we cover the costs of interactions and ways to design around them and to optimize for them.&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/42dd1b2f99ad7eba6c2a7fbfc494cc7a/5a190/webrtc-ux-series-5.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 56.29139072847682%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAACaklEQVQozzVS3UvbcBT1T9L9A2MPY/jQ7cE9DIavIg7GGGMbbILDwRDGEEUGblOHc3VqW9vYD7+SNk3SJulX0nz80qZNbBpjq2nSDieCrPtlc5fzcuEezjn33oEzu2MeWxWJq6oVXdM1TdN13TAazabxr5r/yzSPG4apHzUgrJMWJA443S7PS2vLi9+RSGQXix8SsUOS5hRWUHOiypQrVEGCICGyrCCIdU0XBEEGSsdxB1zXyYv1KMF8npmcHh8NhzeQDPi4cTD2+PnE09eLASxM14IE2MLBdgKTJbHdbgMAqmrNI3e7LsOrOEunIkv+uTcilwylisO+kaHBG0ODQ/cfjCJ0LZbTQ1SF4RTXcexOx7IsGMKz7bouW1b3qWyaiK75FzmZ/RpGH42PvZt6Nfny2T2fb341sseZQUJJM9xp66Tf75+fnx81jL+ZHack14OEvE3KgbQE8eTF1Lcvc5UiVuPwmbeTd4Z9/l0WYbQ9nK4A0Gq1bNtumsfXypAcoqoIXU8Um0uh5M1bt3+sLJgS+bPJLbyfvjvycJuQ4QDDK/ZpW5JBr9drNIzTM9tTzhbEAC7BYJGsGstpKwgViKFMKp5LJdYRdAuXEvmjTVwSVAN6/nVxAcUlSb4ms5y8jBD+/fwOq3vrKZibKSGFE+hedB0rRfPNHVbbTAMO6P3+76urq8vLS8NbmOPZzotqIC0H0Vw8C3YoENtdJ0PjfHqVx+aSWxPR/Ug8IwWS5QMy33WdjuNY1glU9k4FG6Wmo3Q5yXhAMyUWXVCoD0VslsPnATXLYp+wTAnL8iRTUFW1UlXhh8BXsTvOH0jOA+tFlfecAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;WebRTC and UX&quot;
        title=&quot;&quot;
        src=&quot;/static/42dd1b2f99ad7eba6c2a7fbfc494cc7a/90cbd/webrtc-ux-series-5.png&quot;
        srcset=&quot;/static/42dd1b2f99ad7eba6c2a7fbfc494cc7a/29fe9/webrtc-ux-series-5.png 151w,
/static/42dd1b2f99ad7eba6c2a7fbfc494cc7a/6728c/webrtc-ux-series-5.png 303w,
/static/42dd1b2f99ad7eba6c2a7fbfc494cc7a/90cbd/webrtc-ux-series-5.png 605w,
/static/42dd1b2f99ad7eba6c2a7fbfc494cc7a/5a190/webrtc-ux-series-5.png 800w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt; &lt;br /&gt;&lt;strong&gt;&lt;a href=&quot;http://developerboards.att.lithium.com/t5/AT-T-Developer-Program-Blogs/7-Simple-ways-to-enhance-the-WebRTC-user-experience/ba-p/40959&quot;&gt;Post #5: Ways to enhance the WebRTC user experience&lt;/a&gt;&lt;/strong&gt; &lt;br /&gt;In the last post in the series, discover ways to further enhance the WebRTC experience and make your application more accessible, private, and user-driven.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Future of Node is in Microsoft’s Fork]]></title><description><![CDATA[Node.js is a platform for running JavaScript (ECMAScript) that is powered by Google Chrome’s JavaScript engine, V8.
V8 pushed JavaScript…]]></description><link>https://blog.andyet.com/2015/12/31/the-future-of-node-is-microsofts-fork/</link><guid isPermaLink="false">https://blog.andyet.com/2015/12/31/the-future-of-node-is-microsofts-fork/</guid><pubDate>Thu, 31 Dec 2015 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Node.js is a platform for running JavaScript (ECMAScript) that is powered by Google Chrome’s JavaScript engine, V8.
V8 pushed JavaScript forward in terms of speed when it was first released, but hasn’t been keeping up with the accelerated pace of the ECMAScript Standard.
We’ll likely see a new release of the spec every year, but V8 is lagging far behind Mozilla’s &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey&quot;&gt;SpiderMonkey&lt;/a&gt; and Microsoft’s &lt;a href=&quot;https://blogs.windows.com/msedgedev/tag/chakracore/&quot;&gt;Chakra&lt;/a&gt; in terms of support for ECMAScript 2015 (aka ES6).&lt;/p&gt;
&lt;p&gt;Node.js developers that have been eager for ES2015 features that V8 doesn&apos;t yet support have turned to &lt;a href=&quot;https://babeljs.io/&quot;&gt;Babel.JS&lt;/a&gt; for compiling their ES2015 code into ES5 code, but this only works for syntax features like &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;arrow functions&lt;/a&gt;.
There are features within ES2015 that Babel.JS can’t emulate because ES5 fundamentally lacks the ability accomplish these features in any reasonable way, namely the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy&quot;&gt;Proxy&lt;/a&gt; constructor and extending built-in objects like Array.&lt;/p&gt;
&lt;p&gt;[Update: &lt;em&gt;This controversial statement has been too distracting.&lt;/em&gt;] &lt;del&gt;&lt;a href=&quot;https://nodejs.org/en/foundation/&quot;&gt;The Node.js Foundation&lt;/a&gt; would be wise to migrate to Chakra, because&lt;/del&gt; Google’s updates are coming in at a trickle while Microsoft’s are roaring in like a river, but that’s not really the point.
The point is that these features are coming regardless, and you can play with them now.
With an annual ECMAScript releases adding new features, Microsoft&apos;s Node.js Chakra fork will continue to outpace Google&apos;s V8 engine by months.
So long as Microsoft maintains their fork, we’ll be able to preview features that aren’t yet ready in V8.&lt;/p&gt;
&lt;p&gt;In order to use Microsoft&apos;s fork, you need a Windows 10 machine with the November update.
It’s a huge update, so just because you have auto-updates enabled doesn’t mean that you have it (this messed me up).
For the full instructions, look at an individual release on github, &lt;a href=&quot;https://github.com/ms-iot/ntvsiot/releases/tag/v1.3&quot;&gt;currently v1.3&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once you have that working, you can play with features that V8 and Babel don&apos;t support, like proxies in this example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; someObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; someProxy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;someObject&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; property&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reciever&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;property&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;happy_&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Reflect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; property&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reciever&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sad&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; property&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reciever&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;property&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;happy_&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Reflect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; property&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reciever&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

someProxy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;happy_x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;happy&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token string&quot;&gt;`someproxy.happy_x = &apos;happy&apos;;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;=&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;someProxy.x:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; someProxy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;someObject.x:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; someObject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;someProxy.happy_x:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; someProxy&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;happy_x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;someObject.happy_x:&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; someObject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;happy_x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;txt&quot;&gt;&lt;pre class=&quot;language-txt&quot;&gt;&lt;code class=&quot;language-txt&quot;&gt;someproxy.happy_x = &amp;#39;happy&amp;#39;;
========================================
someProxy.x = sad
someObject.x = happy
someProxy.happy_x = happy
someObject.happy_x = undefined&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/kangax&quot;&gt;@kangax&lt;/a&gt; maintains an &lt;a href=&quot;https://kangax.github.io/compat-table/es6/&quot;&gt;ECMAScript Compatibility Table&lt;/a&gt; where you can compare support for Node.js and Edge for several versions of ECMAScript so that you know what features to explore with Microsoft&apos;s Node.js fork.&lt;/p&gt;
&lt;p&gt;Feel free to poke me on &lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;Twitter @fritzy&lt;/a&gt; if you have any thoughts or feedback.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Update (Dec 31, 2015):&lt;/p&gt;
&lt;p&gt;There are several people pointing out that Chakra isn&apos;t open source. However, it is &lt;a href=&quot;https://blogs.windows.com/msedgedev/2015/12/05/open-source-chakra-core/&quot;&gt;going open source in January&lt;/a&gt;, and cross platform afterward.&lt;/p&gt;
&lt;p&gt;My main point is not that ChakraCore should be the new Node.js JavaScript engine, but that Microsoft&apos;s fork of Node.js with ChakraCore in it is a pretty handy way to preview Node.js&apos;s future, regardless.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Update (Jan 2, 2015):&lt;/p&gt;
&lt;p&gt;I&apos;ve been receiving a lot of feedback.
I&apos;m removing my statement saying that Node.js should move to Chakra -- that was meant to be controversial and get people thinking, but it has proven distracting to my main point, that you can play with Microsoft&apos;s Fork to preview features that they have that Node.js doesn&apos;t yet have.&lt;/p&gt;
&lt;p&gt;Mikeal Rogers pointed out that I was making an inappropriate suggestion for the Node.js Foundation:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; &amp;quot;The Node.js Foundation&amp;quot; does not make technical decisions, the contributors to Node.js make them :)&lt;/p&gt;&amp;mdash; Mikeal Rogers (@mikeal) &lt;a href=&quot;https://twitter.com/mikeal/status/683145232704094208&quot;&gt;January 2, 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;He goes on to give some more context:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; the code in MS&amp;#39;s fork will be in a PR to core in January, they&amp;#39;ve already announced it. It&amp;#39;ll make it optional to compile w/ Chakra.&lt;/p&gt;&amp;mdash; Mikeal Rogers (@mikeal) &lt;a href=&quot;https://twitter.com/mikeal/status/683145383724204032&quot;&gt;January 2, 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;Several people pointed this out:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; it isn&amp;#39;t clear that Chakra will *always* outpace v8 in ES-WHATEVA features.&lt;/p&gt;&amp;mdash; Mikeal Rogers (@mikeal) &lt;a href=&quot;https://twitter.com/mikeal/status/683145686972416000&quot;&gt;January 2, 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;In fact, Jake Archibald references a tweet showing that the V8 team has been catching up:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/mikeal&quot;&gt;@mikeal&lt;/a&gt; &lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; Canary (albeit with flags) currently has the highest es6 support, &amp;quot;lagging far behind&amp;quot; seems unfair &lt;a href=&quot;https://t.co/9Qae8kURhK&quot;&gt;https://t.co/9Qae8kURhK&lt;/a&gt;&lt;/p&gt;&amp;mdash; Jake Archibald (@jaffathecake) &lt;a href=&quot;https://twitter.com/jaffathecake/status/683208508330868736&quot;&gt;January 2, 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;Mostly, I&apos;m excited to see the Node.js platform have some diverse implementations. I&apos;m hoping we see more of this.&lt;/p&gt;
&lt;p&gt;I mentioned that I recalled a similar Mozilla effort in the past, and Brendan Eich pitched in with the details:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/mikeal&quot;&gt;@mikeal&lt;/a&gt; &lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; &amp;#39;twas a team of three, and all left for Facebook soon after: &lt;a href=&quot;https://twitter.com/sdwilsh&quot;&gt;@sdwilsh&lt;/a&gt; &lt;a href=&quot;https://twitter.com/zpao&quot;&gt;@zpao&lt;/a&gt; &lt;a href=&quot;https://twitter.com/robarnold&quot;&gt;@robarnold&lt;/a&gt; (onstage w/ me at NodeConf 2011).&lt;/p&gt;&amp;mdash; BrendanEich (@BrendanEich) &lt;a href=&quot;https://twitter.com/BrendanEich/status/683155153038385152&quot;&gt;January 2, 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;Personally, I&apos;d love to see Mozilla come back and do this again; diversity makes for a healthier ecosystem.&lt;/p&gt;
&lt;p&gt;This does raise the question: is there a better long term solution for multiple JS engines than V8 API shims?&lt;/p&gt;
&lt;p&gt;Keep the feedback rolling.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Join Us at the Node Community Convention in San Francisco, CA!]]></title><description><![CDATA[Nathan Fritz and Sally Mohr will be presenting at the Node Community Convention on January 26-28th in San Francisco, CA.The Node Community…]]></description><link>https://blog.andyet.com/2015/12/08/join-us-at-the-node-community-convention/</link><guid isPermaLink="false">https://blog.andyet.com/2015/12/08/join-us-at-the-node-community-convention/</guid><pubDate>Tue, 08 Dec 2015 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://andyet.com/team/nathan/&quot;&gt;Nathan Fritz&lt;/a&gt; and &lt;a href=&quot;https://andyet.com/team/sally/&quot;&gt;Sally Mohr&lt;/a&gt; will be presenting at the &lt;a href=&quot;http://nodecommunityconvention.com/&quot;&gt;Node Community Convention&lt;/a&gt; on January 26-28th in San Francisco, CA.&lt;/p&gt;
&lt;p&gt;The Node Community Convention&apos;s focus is to provide the learning space for best practices and new techniques to maximize the use of node.js, case studies from developers and companies who are changing the web, and a networking space to build the personal and professional relationships you need. &lt;/p&gt;
&lt;p&gt;Nathan and Sally will be speaking on &lt;a href=&quot;http://nodecommunityconvention.com/san-francisco-2016/agenda/day-three/145pm.html&quot;&gt;Convincing the Decision Makers to Use Node&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are excited to see you in SF! Come say hi if you&apos;ll be there.&lt;/p&gt;
&lt;p&gt;You can use the discount code &lt;strong&gt;&amp;#x26;yet15&lt;/strong&gt; when you register &lt;a href=&quot;http://nodecommunityconvention.com/san-francisco-2016/register/&quot;&gt;here&lt;/a&gt; and get a &lt;strong&gt;15% discount&lt;/strong&gt; for folks in our &lt;a href=&quot;https://andyet.com/andyou/&quot;&gt;&amp;#x26;you&lt;/a&gt; community.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://nodecommunityconvention.com/ &quot; &gt;&amp;#x3C;img border=&quot;0&quot;src=&quot;http://nodecommunityconvention.com/assets/images/banners/node-728.gif&quot; alt=&quot;Node Community Convention &quot; &gt;&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Modern WebRTC Javascript with Promises]]></title><description><![CDATA[tl;dr: with adapter.js you can write WebRTC code that is spec-compliant and works in all supported browsers. That is the web we want.We have…]]></description><link>https://blog.andyet.com/2015/11/18/modern-webrtc-js/</link><guid isPermaLink="false">https://blog.andyet.com/2015/11/18/modern-webrtc-js/</guid><pubDate>Wed, 18 Nov 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;tl;dr: with adapter.js you can write WebRTC code that is spec-compliant and works in all supported browsers. That is the web we want.&lt;/p&gt;
&lt;p&gt;We have come a long way since WebRTC was first enabled by default in Nightly &lt;a href=&quot;http://www.webrtc.org/blog/webrtcenabledbydefaultinfirefoxnightly&quot;&gt;back in February 2013&lt;/a&gt; after interoperability &lt;a href=&quot;http://www.webrtc.org/blog/firefoxandchromeinteropachieved&quot;&gt;had been achieved&lt;/a&gt; earlier that month. Since then a lot has happened. &lt;/p&gt;
&lt;p&gt;One of the bigger updates to the specifications was the addition of a &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/es6/promises/&quot;&gt;Promise-based version&lt;/a&gt; of the API instead of callback-based API in December 2014. Firefox has supported the Promise-based versions of the getUserMedia and the RTCPeerConnection APIs for quite a while now. Yay! &lt;/p&gt;
&lt;p&gt;That means you can write code like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;  navigator.mediaDevices.enumerateDevices()
  .then(function (devices) {
     // look for audio and video devices, call getUserMedia
    return navigator.mediaDevices.getUserMedia({audio: true, video: true})
  })
  .then(function (stream) {
    // attach to video element
    // attach to peerconnection and establish a connection to the peer
  })
  .catch(function (error) {
    // handle any error that occurred in the chain
  });&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Compare that to the callback-way of doing it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;  navigator.mediaDevices.enumerateDevices(function (devices) {
    // look for audio and video devices, call getUserMedia
   navigator.mediaDevices.getUserMedia({audio: true, video: true},
     function (stream) {
        // attach to video element
        // attach to peerconnection and establish a connection to the peer
     },
     function (error) {
        // handle errors from getUserMedia
     }
  }, function (error) {
    // handle errors from enumerateDevices, often forgotten
  });&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The promise-based version is easier to read and, more importantly, has a single error handler.
With &lt;a href=&quot;https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/&quot;&gt;ES6 and arrow functions&lt;/a&gt; it gets a lot shorter even.&lt;/p&gt;
&lt;p&gt;Now, if you want to write something that is more than a demo, you will quickly notice that there are other browsers out there. Browsers that have not yet caught up with the changes in the specification...&lt;/p&gt;
&lt;p&gt;This is not really a new issue. The RTCPeerConnection and getUserMedia APIs have been prefixed in both Firefox and Chrome since they got introduced in late 2012. One of the ways to work around that has been the &lt;a href=&quot;https://github.com/webrtc/adapter&quot;&gt;adapter.js shim&lt;/a&gt; written by Google’s WebRTC team (oh, and us). It provided a way to detect what browser was used and allows developers to develop against a uniform API.&lt;/p&gt;
&lt;p&gt;Over time, it has grown from a simple script consisting of not much more than&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;    var RTCPeerConnection = mozRTCPeerConnection || webkitRTCPeerConnection;
    var getUserMedia = mozGetUserMedia || webkitGetUserMedia;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;to a rather complex piece of software with &lt;a href=&quot;https://blog.andyet.com/2015/07/28/selenium-travis-webrtc&quot;&gt;unit tests and continuous integration in multiple browsers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Recently, instead of just making things work, adapter.js now aims to make things work in the way the specifications describe them, without waiting for every browser to catch up. Promise-support was one of the first things we got to work and it turned out to be easier than we thought. One just has to overload the native methods &lt;a href=&quot;https://github.com/webrtc/adapter/blob/a46d99db717d88dcb14ae68dfb55880094fd2b31/adapter.js#L304-L344&quot;&gt;as shown here&lt;/a&gt;. The trick is to look at the number of arguments to the function call and the type of the first argument to determine whether the Promise-based version&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;     pc.createOffer(constraints)
    .then(successCallback)
    .catch(errorCallback)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or the legacy variant&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;    pc.createOffer(successCallback, errorCallback, constraints)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;is intended. Pretty amazing what you can do with a little JavaScript. The tests for the &lt;a href=&quot;https://github.com/webrtc/adapter/blob/a46d99db717d88dcb14ae68dfb55880094fd2b31/test/test.js#L510-L563&quot;&gt;legacy version&lt;/a&gt; and the &lt;a href=&quot;https://github.com/webrtc/adapter/blob/a46d99db717d88dcb14ae68dfb55880094fd2b31/test/test.js#L565-L617&quot;&gt;Promise-based version&lt;/a&gt; show the difference quite nicely. The test for the legacy API is 53 lines long and indented 12 levels. The promise-based test is 19 lines and indented only one level, making it much easier to read.&lt;/p&gt;
&lt;p&gt;The list of differences hidden by adapter goes on...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;overloading getUserMedia to support the &lt;a href=&quot;http://w3c.github.io/mediacapture-main/#constrainable-interface&quot;&gt;constraint for specifying the video capture resolution&lt;/a&gt; (Chrome is natively using an old format, see here for the &lt;a href=&quot;https://webrtc.github.io/samples/src/content/getusermedia/resolution/&quot;&gt;new way&lt;/a&gt; to do it),&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://w3c.github.io/mediacapture-main/#mediastreamconstraints&quot;&gt;enumerating available devices&lt;/a&gt; (since added to Chrome 47), &lt;/li&gt;
&lt;li&gt;changing the format of the &lt;a href=&quot;http://w3c.github.io/webrtc-stats/&quot;&gt;returned statistics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;even completly different APIs like ORTC!&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is stuff you can do with javascript now, instead of waiting for the browsers to catch up.&lt;/p&gt;
&lt;p&gt;One of the last big remaining issues was the lack of support for setting the srcObject property of video tags so that you can attach a MediaStream to them. In the past, adapter.js has used two helper functions, attachMediaStream and reattachMediaStream, to hide the different ways which have to be used in Chrome and Firefox.
Mozilla has supported mozSrcObject in a prefixed version for a very long time now and Firefox 42 &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1175523&quot;&gt;will unprefix it&lt;/a&gt;. Chrome does not support this and still requires the src property to be set to an object URL. &lt;/p&gt;
&lt;p&gt;Now how do you control the behavior of HTML elements? The answer was given by Chrome developer &lt;a href=&quot;https://developers.google.com/web/updates/2015/04/DOM-attributes-now-on-the-prototype-chain&quot;&gt;Paul Kinlan recently&lt;/a&gt;: you just define setters and getters on the HTMLMediaElement’s prototype as &lt;a href=&quot;https://github.com/webrtc/adapter/blob/a46d99db717d88dcb14ae68dfb55880094fd2b31/adapter.js#L50-L70&quot;&gt;shown here&lt;/a&gt;. Which means you can just write the following:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;   navigator.mediaDevices.getUserMedia({video: true})
   .then(function (stream) {
     document.getElementById(‘localVideo’).srcObject = stream;
   })&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This way, the &lt;a href=&quot;https://dev.modern.ie/testdrive/demos/photocapture/&quot;&gt;Microsoft Edge demos for getUserMedia&lt;/a&gt; require no changes to work in other browsers like Firefox and Chrome. Plus there is no need to fall back to helper functions just because some browsers are lagging behind the standard.&lt;/p&gt;
&lt;p&gt;All the webrtc.org samples, one of the most useful developer resources out there, have been updated to use this instead of the old attachMediaStream helper. Because there is nothing worse than teaching developers the wrong way to do things. Writing standards-compliant code that just works is the Web we want.&lt;/p&gt;
&lt;p&gt;If you find this as helpful as I do, please give thanks to &lt;a href=&quot;https://github.com/alvestrand&quot;&gt;Harald Alvestrand&lt;/a&gt;, &lt;a href=&quot;https://github.com/jan-ivar&quot;&gt;Jan-Ivar Bruaroey&lt;/a&gt; and &lt;a href=&quot;https://github.com/kaptenjansson&quot;&gt;Christoffer Jansson&lt;/a&gt; for working together on this.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Building WebRTC with Bitcode]]></title><description><![CDATA[Back in June, Apple introduced bitcode as a part of their app thinning strategy, which allows them to implement some optimizations in the…]]></description><link>https://blog.andyet.com/2015/10/20/building-webrtc-with-bitcode/</link><guid isPermaLink="false">https://blog.andyet.com/2015/10/20/building-webrtc-with-bitcode/</guid><pubDate>Tue, 20 Oct 2015 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Back in June, Apple introduced &lt;a href=&quot;https://developer.apple.com/library/prerelease/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AppThinning/AppThinning.html#//apple_ref/doc/uid/TP40012582-CH35-SW2&quot;&gt;bitcode&lt;/a&gt; as a part of their app thinning strategy, which allows them to implement some optimizations in the future without developers having to resubmit their apps. Unfortunately, bitcode must be enabled for the whole app, including third-party libraries. This is a problem if you use WebRTC as it does not currently have a build option to enable bitcode.&lt;/p&gt;
&lt;p&gt;Because the &lt;a href=&quot;https://itunes.apple.com/us/app/talky-free-video-chat-group/id882057960&quot;&gt;Talky iOS app&lt;/a&gt; uses WebRTC, I decided to investigate what it would take to enable bitcode when building WebRTC. For this post, I assume that you&apos;re building a Release build of WebRTC with the steps outlined at &lt;a href=&quot;http://www.webrtc.org/native-code/ios&quot;&gt;http://www.webrtc.org/native-code/ios&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;step-1-get-the-code&quot;&gt;&lt;a href=&quot;#step-1-get-the-code&quot; aria-label=&quot;step 1 get the code permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 1: Get the code&lt;/h2&gt;
&lt;p&gt;If you haven&apos;t already downloaded the WebRTC source, open a terminal window and follow the steps for &lt;a href=&quot;http://www.webrtc.org/native-code/ios&quot;&gt;&quot;Getting the code&quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Warning: Due to the size of the repository and its dependencies, this could take a while.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;step-2-point-to-the-right-version-of-xcode&quot;&gt;&lt;a href=&quot;#step-2-point-to-the-right-version-of-xcode&quot; aria-label=&quot;step 2 point to the right version of xcode permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 2: Point to the right version of Xcode&lt;/h2&gt;
&lt;p&gt;Only Xcode 7 and above can produce bitcode. If you only have Xcode 7 installed, you can skip this step. I tend to have a &lt;a href=&quot;https://forums.developer.apple.com/thread/19218#60430&quot;&gt;few versions of Xcode installed&lt;/a&gt;, so I like to make sure I&apos;m using the right one for command-line builds.&lt;/p&gt;
&lt;p&gt;In a terminal window, run the following command to set the path to a copy of Xcode 7:&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;sudo xcode-select -s &amp;quot;/Applications/Xcode-beta.app/&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In this case, I&apos;m pointing to my copy of Xcode 7.1 Beta.&lt;/p&gt;
&lt;h2 id=&quot;step-3-link-libicucore-can-skip-if-youre-on-commit-fd4df46-or-above-of-webrtc&quot;&gt;&lt;a href=&quot;#step-3-link-libicucore-can-skip-if-youre-on-commit-fd4df46-or-above-of-webrtc&quot; aria-label=&quot;step 3 link libicucore can skip if youre on commit fd4df46 or above of webrtc permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 3: Link libicucore (can skip if you&apos;re on commit fd4df46 or above of WebRTC)&lt;/h2&gt;
&lt;p&gt;If you&apos;re on commit &lt;a href=&quot;https://chromium.googlesource.com/external/webrtc/+/fd4df46fc6dbb4fd5aeb3ae4a7275cb65b02933c&quot;&gt;fd4df46fc6dbb4fd5aeb3ae4a7275cb65b02933c (r9866)&lt;/a&gt; from 2015-09-05 or above of WebRTC, you can skip this step.&lt;/p&gt;
&lt;p&gt;Due to some &lt;a href=&quot;https://forums.developer.apple.com/message/8609#8609&quot;&gt;changes in Xcode 7&lt;/a&gt;, you&apos;ll need to change how the icucore library is linked. Open &lt;code class=&quot;language-text&quot;&gt;webrtc/libjingle_example.gyp&lt;/code&gt; in your editor of choice and change the section (line 339 as of this writing) that looks like&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;#39;link_settings&amp;#39;: {
  &amp;#39;xcode_settings&amp;#39;: {
    &amp;#39;OTHER_LDFLAGS&amp;#39;: [
      &amp;#39;-framework CFNetwork&amp;#39;,
    ],
  },
  &amp;#39;libraries&amp;#39;: [
    &amp;#39;$(SDKROOT)/usr/lib/libicucore.dylib&amp;#39;,
  ],
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;to look like&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;#39;link_settings&amp;#39;: {
  &amp;#39;xcode_settings&amp;#39;: {
    &amp;#39;OTHER_LDFLAGS&amp;#39;: [
      &amp;#39;-framework CFNetwork&amp;#39;,
      &amp;#39;-licucore&amp;#39;,
    ],
  },
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Note: If you need to follow this step, you&apos;ll need to repeat this anytime you update WebRTC until you&apos;ve passed the commit mentioned above or your local changes may be overwritten.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;step-4-enable-bitcode&quot;&gt;&lt;a href=&quot;#step-4-enable-bitcode&quot; aria-label=&quot;step 4 enable bitcode permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 4: Enable bitcode&lt;/h2&gt;
&lt;p&gt;To actually enable bitcode, we need to &lt;a href=&quot;https://forums.developer.apple.com/thread/3971#9821&quot;&gt;add a flag&lt;/a&gt; to the build configuration. I added it to &lt;code class=&quot;language-text&quot;&gt;build/common.gypi&lt;/code&gt; to make sure it was applied to every dependency. Open &lt;code class=&quot;language-text&quot;&gt;build/common.gypi&lt;/code&gt; in your editor of choice and change the section (line 3469 as of this writing) that looks like&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;#39;xcode_settings&amp;#39;: {
  &amp;#39;DEAD_CODE_STRIPPING&amp;#39;: &amp;#39;YES&amp;#39;,  # -Wl,-dead_strip
  &amp;#39;GCC_OPTIMIZATION_LEVEL&amp;#39;: &amp;#39;&amp;lt;(mac_release_optimization)&amp;#39;,
  &amp;#39;OTHER_CFLAGS&amp;#39;: [ &amp;#39;&amp;lt;@(release_extra_cflags)&amp;#39;, ],
},&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;to look like&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;#39;xcode_settings&amp;#39;: {
  &amp;#39;DEAD_CODE_STRIPPING&amp;#39;: &amp;#39;YES&amp;#39;,  # -Wl,-dead_strip
  &amp;#39;GCC_OPTIMIZATION_LEVEL&amp;#39;: &amp;#39;&amp;lt;(mac_release_optimization)&amp;#39;,
  &amp;#39;OTHER_CFLAGS&amp;#39;: [ &amp;#39;&amp;lt;@(release_extra_cflags)&amp;#39;, &amp;#39;-fembed-bitcode&amp;#39;, ],
},&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Note: You&apos;ll need to repeat this anytime you update WebRTC or your local changes may be overwritten.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;step-5-use-the-right-compiler&quot;&gt;&lt;a href=&quot;#step-5-use-the-right-compiler&quot; aria-label=&quot;step 5 use the right compiler permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 5: Use the right compiler&lt;/h2&gt;
&lt;p&gt;By default, the build process for WebRTC uses a bundled version of Clang which does not support bitcode. So we need to tell it to use the version of Clang included with Xcode (specifically Xcode 7; see &lt;a href=&quot;#step-2-point-to-the-right-version-of-xcode&quot;&gt;Step 2&lt;/a&gt;) instead.&lt;/p&gt;
&lt;p&gt;When following the steps for &lt;a href=&quot;http://www.webrtc.org/native-code/ios&quot;&gt;&quot;Compiling the code&quot;&lt;/a&gt;, add &lt;code class=&quot;language-text&quot;&gt;clang_xcode=1&lt;/code&gt; to your &lt;code class=&quot;language-text&quot;&gt;GYP_DEFINES&lt;/code&gt; environment variable. As an example, here&apos;s the full value for a 32-bit iOS build:&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;export GYP_DEFINES=&amp;quot;OS=ios target_arch=arm clang_xcode=1&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&quot;step-6-compile&quot;&gt;&lt;a href=&quot;#step-6-compile&quot; aria-label=&quot;step 6 compile permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 6: Compile&lt;/h2&gt;
&lt;p&gt;Follow the steps for &lt;a href=&quot;http://www.webrtc.org/native-code/ios&quot;&gt;&quot;Compiling the code&quot;&lt;/a&gt; remembering to adjust the instructions as per Step 5.&lt;/p&gt;
&lt;h2 id=&quot;step-7-verify&quot;&gt;&lt;a href=&quot;#step-7-verify&quot; aria-label=&quot;step 7 verify permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 7: Verify&lt;/h2&gt;
&lt;p&gt;To verify that the build actually includes bitcode, open the &lt;code class=&quot;language-text&quot;&gt;out_ios/Release-iphoneos&lt;/code&gt; directory. In a terminal window, run &lt;code class=&quot;language-text&quot;&gt;otool -l &amp;lt;static-library&amp;gt; | grep __LLVM&lt;/code&gt;. As an example:&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;otool -l libjingle_peerconnection.a | grep __LLVM&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;According to this &lt;a href=&quot;https://forums.developer.apple.com/thread/3971#11560&quot;&gt;forum post&lt;/a&gt;, the presence of the &lt;code class=&quot;language-text&quot;&gt;__LLVM&lt;/code&gt; segment is the best way to determine if the files you just built contain bitcode.&lt;/p&gt;
&lt;h2 id=&quot;step-8-done&quot;&gt;&lt;a href=&quot;#step-8-done&quot; aria-label=&quot;step 8 done permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step 8: Done!&lt;/h2&gt;
&lt;p&gt;You now have a build of WebRTC that include bitcode.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Talky gets Real-time Text]]></title><description><![CDATA[Today I'm pleased to announce the release of a new feature of our video conferencing service, Talky.io. It's called Real-time Text (or RTT…]]></description><link>https://blog.andyet.com/2015/10/19/talky-gets-real-time-text/</link><guid isPermaLink="false">https://blog.andyet.com/2015/10/19/talky-gets-real-time-text/</guid><pubDate>Mon, 19 Oct 2015 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today I&apos;m pleased to announce the release of a new feature of our video conferencing service, &lt;a href=&quot;https://talky.io&quot;&gt;Talky.io&lt;/a&gt;. It&apos;s called Real-time Text (or RTT for short), and it lets other people in your Talky room see what you are typing into the room chat, as you type. Here&apos;s a screen capture of RTT in action:&lt;/p&gt;
&lt;video controls autoplay loop class=&apos;with-border&apos; alt=&apos;Screencapture of RTT in action&apos;&gt;
  &lt;source src=&apos;/uploads/talky-gets-real-time-text.mp4&apos; type=&apos;video/mp4&apos; /&gt;
  &lt;source src=&apos;/uploads/talky-gets-real-time-text.webm&apos; type=&apos;video/webm&apos; /&gt;
  &lt;img src=&apos;/uploads/talky-gets-real-time-text.png&apos; alt=&apos;Screencapture of RTT in action&apos; /&gt;
&lt;/video&gt;
&lt;p&gt;RTT is not enabled by default as most people are inclined to hide typos or half-finished thoughts, but you can opt-in by ticking the &quot;Send as I type&quot; box beneath the chat input. &lt;/p&gt;
&lt;p&gt;So why add RTT to Talky? Because at &amp;#x26;yet we believe that software is about people, and there are people who use Talky that are not able to use the voice half of our voice and video service. &lt;/p&gt;
&lt;p&gt;One of &lt;a href=&quot;http://andyetconf.com&quot;&gt;&amp;#x26;yetConf&lt;/a&gt;&apos;s opening night speakers, &lt;a href=&quot;https://twitter.com/ChouGyver&quot;&gt;Aimee Chou&lt;/a&gt;, talked about her experiences as a deaf person, both in terms of conferences and software. (In fact, she gave her presentation in sign language, and it was the audience who had an interpreter.) As she put it, deaf users are treated as &quot;edge-cases&quot;.&lt;/p&gt;
&lt;p&gt;Many software developers think it&apos;s OK to not bother supporting people who are hearing impaired, or simply aren&apos;t aware of how the user experience of their app changes when a person can&apos;t hear. &lt;/p&gt;
&lt;p&gt;Given that audio and voice is a large part of what I work on, I was especially impacted by her plea to be considered when building apps. So I ended up skipping most of the conference talks to focus on bringing RTT to Talky.&lt;/p&gt;
&lt;p&gt;Real-time Text is an important feature for deaf and hard-of-hearing folks, because it lets them have a close approximation to &quot;voice&quot;. Without RTT, the options are to use some form of sign language or rely on normal text chat. But text chat is slow for live conversations. It usually doesn&apos;t feel that way, but it becomes readily apparent when you have video. There are lots of starts and stops, pausing the video conversation experience while you type or read a message. And a lot of the time you aren&apos;t even able to maintain eye contact, because you&apos;re both always looking off to the side at the chat to read the latest message. &lt;/p&gt;
&lt;p&gt;The purpose of RTT is to make the text chat mimic the speed and bandwidth of voice. You don&apos;t have to finish a paragraph for the other person to respond, they&apos;re already answering before you finished! You can see the emotions of the person both from their face on video and from the cadence and intensity of their typing -- the fast keypresses from heightened emotions, the slow adding and changing of words when the speaker is unsure. All of these little cues that we are accustomed (even if unknowingly) to interpreting and applying to our understanding of the other person in the conversation are important, and with RTT those cues can be recreated, at least in part. Just as importantly, we can place the live text on top of the person&apos;s video so that you are both looking at each other so you can see the emotions on each other&apos;s faces as you type.&lt;/p&gt;
&lt;p&gt;Real-time text is not a new thing. You might remember similar things from the heydays of AIM and ICQ. For Talky, we use &lt;a href=&quot;http://xmpp.org&quot;&gt;XMPP&lt;/a&gt; for our signaling, and so we now use the &lt;a href=&quot;http://xmpp.org/extensions/xep-0301.html&quot;&gt;In-Band Real Time Text&lt;/a&gt; standard written by Mark Rejhon and Gunnar Hellstrom. As a member of the XMPP Standards Foundation, I was involved in the standardization process of that document back in 2011 and 2012, providing feedback on various portions. So when we converted Talky to use XMPP in 2014, I actually added support for RTT to our &lt;a href=&quot;http://stanza.io&quot;&gt;stanza.io&lt;/a&gt; XMPP library. Sadly, I then never got around to actually integrating RTT into Talky, which made Aimee&apos;s words strike me all the harder. &lt;/p&gt;
&lt;p&gt;The naive approach to implementing some form of RTT would be to send keystrokes as they happen. That&apos;s what it sounds and looks like you&apos;re doing, after all. But there are more ways that text can change than just keystrokes (for example, your OS or browser might perform spell correction automatically). So what we do is whenever the chat input text is modified in any way we perform a simple diff calculation to see what text was added or removed. I say &quot;simple&quot; here, because we can generally assume that there is only one cursor and therefore only one spot is realistically able to be changed between diff checks. That diff is then saved in a queue, along with the time since the last diff event. Every 700 milliseconds or so, that queue is drained and all of the events sent to the other conversation participants, who are then able to &quot;replay&quot; those events, including the delays, to simulate the process of how the text was originally typed.&lt;/p&gt;
&lt;p&gt;There are of course more little implementation details and potential Unicode issues that the &lt;a href=&quot;http://xmpp.org/extensions/xep-0301.html&quot;&gt;XEP-0301&lt;/a&gt; spec covers, but the fundamental model is remarkably simple and fun to implement.&lt;/p&gt;
&lt;p&gt;Since Talky&apos;s earliest days, we&apos;ve received many kind and encouraging notes from members of the deaf community. We&apos;re thrilled to be able to add this feature for those users and more.&lt;/p&gt;
&lt;p&gt;Give real-time text a try the next time you use Talky (it also pairs very well with our new &lt;a href=&quot;https://blog.andyet.com/2015/10/16/talky-for-smaller-screens&quot;&gt;small screen support&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;We&apos;re looking forward to your feedback!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Talky for smaller screens]]></title><description><![CDATA[A piece of recurring feedback we’ve received is that the Talky web interface isn’t great for smaller screens, especially for those on…]]></description><link>https://blog.andyet.com/2015/10/16/talky-for-smaller-screens/</link><guid isPermaLink="false">https://blog.andyet.com/2015/10/16/talky-for-smaller-screens/</guid><pubDate>Fri, 16 Oct 2015 12:32:00 GMT</pubDate><content:encoded>&lt;p&gt;A piece of recurring feedback we’ve received is that the Talky web interface isn’t great for smaller screens, especially for those on Android mobile devices. There is a Talky iOS app, but there isn’t one yet for Android, and the web interface was designed for wider (desktop-sized) screens.&lt;/p&gt;
&lt;p&gt;With the latest release, we’ve taken that feedback and designed a better experience for small screens. Our primary goal was freeing up screen space for the video streams. We changed the wide sidebar to a much shorter top navigation, but keeping the primary controls readily available. To gain back some space, we moved the less-frequently used controls into an expandable menu and removed the secondary roster of participants.&lt;/p&gt;
&lt;img src=&apos;/uploads/talky-small-screens.jpg&apos; alt=&apos;Talky for smaller screens&apos; class=&apos;with-border&apos; /&gt;
&lt;p&gt;While these changes were made with mobile devices in mind, you can also see them on your desktop browser. Resize your browser window and free up some of that monitor space.&lt;/p&gt;
&lt;p&gt;Check it out now at &lt;a href=&quot;https://talky.io&quot;&gt;talky.io&lt;/a&gt; and let us know what you think! Or tell us what other features you’d love to see added to Talky.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[World’s first conference calls between Chrome, Firefox, and Microsoft Edge]]></title><description><![CDATA[We’ve talked before about the revolutionary importance of WebRTC, because it brings the principles of the open web to voice, video…]]></description><link>https://blog.andyet.com/2015/09/29/ortc-demo/</link><guid isPermaLink="false">https://blog.andyet.com/2015/09/29/ortc-demo/</guid><pubDate>Tue, 29 Sep 2015 14:30:00 GMT</pubDate><content:encoded>&lt;p&gt;We’ve talked before about the revolutionary importance of WebRTC, because it &lt;a href=&quot;https://blog.andyet.com/2014/12/10/webrtc-and-the-web-we-want&quot;&gt;brings the principles of the open web&lt;/a&gt; to voice, video, screensharing, and other applications that were traditionally closed off to fast innovation. This revolution has been led not by old-style telcos but by web and mobile companies, especially the developers of the Google Chrome and Mozilla Firefox browsers.&lt;/p&gt;
&lt;p&gt;Until recently, both Microsoft and Apple have been standing on the sidelines as this revolution unfolded. Thankfully that’s starting to change, as Microsoft adds these capabilities to its upcoming Edge browser. (Apple, however, is still late to the party.)&lt;/p&gt;
&lt;p&gt;There’s a twist to this story, though, because Edge supports an object-oriented flavor of WebRTC called &lt;a href=&quot;https://blog.andyet.com/2014/11/18/ortc&quot;&gt;ORTC&lt;/a&gt;, which most observers expect will eventually become WebRTC 1.1 or 2.0 or something. :-)&lt;/p&gt;
&lt;p&gt;Thus we have a conundrum: in video conferencing apps like our &lt;a href=&quot;https://talky.io/&quot;&gt;Talky service&lt;/a&gt;, cross-browser calls work fine right now because &lt;a href=&quot;http://blog.chromium.org/2013/02/hello-firefox-this-is-chrome-calling.html&quot;&gt;both Chrome and Firefox support WebRTC&lt;/a&gt;. But adding Edge to the mix doesn’t automatically result in cross-browser calls to Edge users, since the signaling methods involved have different syntax even though the semantics are the same.&lt;/p&gt;
&lt;p&gt;The solution is to &lt;a href=&quot;https://blog.andyet.com/2015/04/22/webrtc-and-ortc&quot;&gt;hide some of the messy details&lt;/a&gt; from app developers by providing a higher-level API - ideally one that’s more object-oriented because as a developer do you really want to be dealing with &lt;a href=&quot;http://www.rfc-editor.org/rfc/rfc4566.txt&quot;&gt;Session Description Protocol&lt;/a&gt;? We didn’t think so.&lt;/p&gt;
&lt;p&gt;We care a lot about interoperability, so yetis &lt;a href=&quot;https://andyet.com/team/fippo&quot;&gt;Philipp Hancke, aka fippo&lt;/a&gt; and &lt;a href=&quot;https://andyet.com/team/lance&quot;&gt;Lance Stout&lt;/a&gt; jumped at the chance to gain early access to the ORTC API in Edge when Microsoft sent us an invitation to visit them in Redmond.&lt;/p&gt;
&lt;p&gt;We plan to publish several reports on our work in this area, covering a lot of fascinating technical internals. For now, we simply must point to the demo that fippo built using &lt;a href=&quot;https://simplewebrtc.com/&quot;&gt;SimpleWebRTC&lt;/a&gt; because it represents a huge advance in the state of the art: the world’s first interoperable conference calling app that supports Chrome, Firefox, and now Edge, too!&lt;/p&gt;
&lt;p&gt;The folks at Microsoft are featuring the demo on &lt;a href=&quot;https://dev.modern.ie/testdrive/demos/simplewebrtc/&quot;&gt;the dev.modern.ie testdrive&lt;/a&gt; so head on over and give it a try.&lt;/p&gt;
&lt;p&gt;As you can see, we’re always on the cutting edge (no pun intended) of WebRTC, ORTC, and whatever is next in the field of realtime communication. To get a jump start on building the realtime app of your dreams, &lt;a href=&quot;https://andyet.com/talky&quot;&gt;drop us a line today&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What the heck, why not? A sneak peek]]></title><description><![CDATA[There have been some questions about what to expect at &yetConf next month. Here's a sneak peek at local artist Husaya Hama, from the Urban…]]></description><link>https://blog.andyet.com/2015/09/17/andyetconf-sneak-peek/</link><guid isPermaLink="false">https://blog.andyet.com/2015/09/17/andyetconf-sneak-peek/</guid><pubDate>Thu, 17 Sep 2015 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There have been some questions about what to expect at &lt;a href=&quot;http://andyetconf.com&quot;&gt;&amp;#x26;yetConf&lt;/a&gt; next month. Here&apos;s a sneak peek at local artist &lt;a href=&quot;http://www.urbanpoetssociety.com/&quot;&gt;Husaya Hama, from the Urban Poets Society,&lt;/a&gt; spoken word piece “Lazer Beams” in response to the themes we’ll be presenting at this year‘s event.&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/139535576?title=0&amp;byline=0&amp;portrait=0&quot; width=&quot;500&quot; height=&quot;270&quot; frameborder=&quot;0&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt; &lt;p&gt;&lt;a href=&quot;https://vimeo.com/139535576&quot;&gt;&amp;amp;yetConf Oct 6-8&lt;/a&gt; from &lt;a href=&quot;https://vimeo.com/andyet&quot;&gt;&amp;amp;yet&lt;/a&gt; on &lt;a href=&quot;https://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We’ve also added lots of updates to the conference site &lt;a href=&quot;http://andyetconf.com&quot;&gt;(andyetconf.com)&lt;/a&gt;, among them some very important ones like – the early bird ticket application process has come to a close! &lt;strong&gt;Regular &lt;a href=&quot;https://ti.to/&amp;#x26;yet/conf-2015&quot;&gt;tickets&lt;/a&gt; are now on sale for $1399&lt;/strong&gt;, but they’re limited so don’t wait too long.&lt;/p&gt;
&lt;p&gt;There’s a &lt;a href=&quot;https://ti.to/&amp;#x26;yet/conf-2015&quot;&gt;discounted ticket&lt;/a&gt; for our local folks who won’t be needing hotel or breakfast.&lt;/p&gt;
&lt;p&gt;Couples attending the conference together this year will have the option of joint attendance, in lieu of a significant others track – essentially for $1699 couples will receive 2 regular tickets + room and board. &lt;/p&gt;
&lt;p&gt;Families traveling together will also have the option of participating in a family track with activities or utilizing onsite childcare. &lt;/p&gt;
&lt;p&gt;We would still love to have more sponsored diversity scholarships, so &lt;strong&gt;please reach out if you can contribute toward helping someone from a marginalized group attend&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Surprisingly, Richland is not an epicenter of metropolitan hustle and bustle, so some folks have questions about &lt;a href=&quot;http://airportcod.es/#airport/psc&quot;&gt;how to get here&lt;/a&gt;. We’ve added travel details to help you plan your route. &lt;/p&gt;
&lt;p&gt;For more answers to questions or to reach out about the conference, please contact us at &lt;a href=&quot;mailto:conf@andyet.com&quot;&gt;conf@andyet.com&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[A microservices case study: Auth]]></title><description><![CDATA[When writing your APIs for a microservice, special care should be taken to properly plan out auth and permissions since parts of your user…]]></description><link>https://blog.andyet.com/2015/09/14/yeti-threads-case-study-auth/</link><guid isPermaLink="false">https://blog.andyet.com/2015/09/14/yeti-threads-case-study-auth/</guid><pubDate>Mon, 14 Sep 2015 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When writing your APIs for a microservice, special care should be taken to properly plan out auth and permissions since parts of your user system will be handled by other services. &lt;a href=&quot;https://blog.andyet.com/2015/09/02/yeti-threads-case-study-pt-1&quot;&gt;Previously, we introduced&lt;/a&gt; &lt;a href=&quot;https://github.com/andyet/yeti-threads&quot;&gt;Yeti Threads&lt;/a&gt; as a case study for writing microservices in Node.js. This time, we’ll be diving into the Auth strategy in this case study.  &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cldup.com/s3fIcU4Zcv.png&quot; alt=&quot;Yeti Threads illustration by Lynn Fisher&quot;&gt;&lt;/p&gt;
&lt;p&gt;“Auth” is really short for two things, &lt;strong&gt;auth&lt;/strong&gt;entication and &lt;strong&gt;auth&lt;/strong&gt;orization. Microservices don’t provide their own authentication, but they’re in charge of at least enforcing their own authorization, if not tracking the permissions as well. In this case, &lt;a href=&quot;http://openid.net/connect/&quot;&gt;OpenID Connect&lt;/a&gt; gives us a &lt;a href=&quot;http://jwt.io/&quot;&gt;JWT token&lt;/a&gt; encoded with a user identity and scopes of authorization (perhaps from &lt;a href=&quot;https://auth0.com/&quot;&gt;Auth0&lt;/a&gt;, or one that we at &lt;a href=&quot;https://andyet.com&quot;&gt;&amp;#x26;yet&lt;/a&gt; helped you customize and deploy). The microservice can trust these values because they’re signed by a private key that only the services themselves know, and can validate the signature. The scopes are a list of tags, typically indicating which sets of actions and endpoints are allowed.&lt;/p&gt;
&lt;p&gt;In Yeti Threads, you might notice that we don’t have a users table in the database. Since we trust the identity and scopes in the &lt;a href=&quot;http://jwt.io/&quot;&gt;signed JWT&lt;/a&gt;, we can simply treat the user id as an opaque string; it doesn’t matter what it is, as long as it uniquely identifies a user. I also decided that I didn’t need a scope for most actions, except for modifying permissions, in which case we need them to have &apos;forum_admin&apos; in their scopes. Look at the &lt;a href=&quot;https://github.com/andyet/yeti-threads/blob/master/controllers/access.js&quot;&gt;access.js controller&lt;/a&gt; and you’ll see that the handlers specify an &lt;code class=&quot;language-text&quot;&gt;auth.scope&lt;/code&gt; (which is a handy hapi handler feature).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    strategy&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;token&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    scope&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;forum_admin&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You may want to have a scope that is required to use any of the API endpoints per microservice, but in this case, I decided that most people can use a commenting system.&lt;/p&gt;
&lt;p&gt;Most of a user’s permissions are tracked by forum in the database. Specifically, we need to know what a user can do on a forum level. Since the forum is specific to this microservice, and spans many ids, it makes sense to track it in the database rather than managing scopes for this. Can you imaging having a scope for every forum id?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TABLE&lt;/span&gt; forums_access &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    user_id &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    forum_id &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REFERENCES&lt;/span&gt; forum&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BOOLEAN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;FALSE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;BOOLEAN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;FALSE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    post &lt;span class=&quot;token keyword&quot;&gt;BOOLEAN&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;FALSE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;KEY&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forum_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Read permissions are handled by joining to the &lt;a href=&quot;https://github.com/andyet/yeti-threads/blob/cc00959b411f62393702ea4f4780e30388e2fe1c/sql/structure.sql#L61-L68&quot;&gt;forum_access table&lt;/a&gt;, which filters out rows that don’t have &lt;code class=&quot;language-text&quot;&gt;forum_access.read&lt;/code&gt; set to &lt;code class=&quot;language-text&quot;&gt;True&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;Post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerFactorySQL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;get&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    sql&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;SELECT posts.id, posts.author, posts.body, posts.parent_id, posts.thread_id, posts.path, posts.created, posts.updated FROM posts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;JOIN threads ON posts.thread_id=threads.id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;JOIN forums ON threads.forum_id=forums.id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;JOIN forums_access ON forums_access.forum_id=forums.id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;WHERE posts.id=$post_id AND ((forums_access.user_id=$user_id AND forums_access.read=True) OR forums.owner=$user_id)&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    oneResult&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Write actions are checked explicitly in their &lt;a href=&quot;https://github.com/andyet/yeti-threads/blob/cc00959b411f62393702ea4f4780e30388e2fe1c/sql/create-update.sql#L6&quot;&gt;database function&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; check_write_access&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userid &lt;span class=&quot;token keyword&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; f_id &lt;span class=&quot;token keyword&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; void &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; forums_access &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; user_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;userid &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; forum_id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;f_id &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; id &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; forums &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; owner&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;userid &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;f_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt;
            RAISE &lt;span class=&quot;token string&quot;&gt;&apos;User lacks permission to write to forum: %&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; f_id &lt;span class=&quot;token keyword&quot;&gt;USING&lt;/span&gt; ERRCODE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;insufficient_privilege&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;language&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;plpgsql&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;PERFORM check_write_access&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forum&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;parent_id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;::&lt;span class=&quot;token keyword&quot;&gt;integer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Any time a forum is created or updated, a &lt;a href=&quot;https://github.com/andyet/yeti-threads/blob/cc00959b411f62393702ea4f4780e30388e2fe1c/sql/trigger-funcs.sql#L41-L56&quot;&gt;database trigger is called&lt;/a&gt; which gives them access to their own forum. Otherwise, the only way to change permissions is to have the &quot;forum_admin&quot; scope assigned by the authentication service to use the &quot;access&quot; routes as mentioned above.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; log_forums_change&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;trigger&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;DECLARE&lt;/span&gt;
  id &lt;span class=&quot;token keyword&quot;&gt;bigint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; TG_OP &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;INSERT&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; TG_OP &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;UPDATE&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt;
    id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; TG_OP &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;INSERT&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;owner &lt;span class=&quot;token operator&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; forums_access &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;user_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; forum_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;owner&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;ELSE&lt;/span&gt;
    id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; OLD&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INTO&lt;/span&gt; forums_log &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;forum_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tbl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TG_TABLE_NAME&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TG_OP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;LANGUAGE&lt;/span&gt; plpgsql&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function also adds to a log, which we’ll get into for live events in a future post.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: Some companies have a permissions microservice for managing and getting user permission. If you’re doing row or object-level permissions on reads, separating it out that way could create a lot of overhead in interservice API requests. Generally, scopes provide a good way for dealing with permissions to features and local permission tracking within a service better handles that service contextually for individual objects.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For actually handling the JWT tokens, we’re using &lt;a href=&quot;https://www.npmjs.com/package/hapi-auth-jwt&quot;&gt;hapi-auth-jwt&lt;/a&gt; and a &lt;a href=&quot;https://github.com/andyet/yeti-threads/blob/cc00959b411f62393702ea4f4780e30388e2fe1c/index.js#L13-L23&quot;&gt;short validate function&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;auth&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;token&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;jwt&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    key&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jwtKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;validateFunc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;decoded&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; credentials &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; decoded&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;credentials&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; credentials&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; credentials&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: After I wrote this, I discovered &lt;a href=&quot;https://www.npmjs.com/package/hapi-auth-jwt2&quot;&gt;hapi-auth-jwt2&lt;/a&gt;, which provides some extra functionality which I haven’t yet needed. I may update Yeti Threads to use it since it’s had more recent commits.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since JSON Web Tokens are stateless, there’s no need to check against the database -- they either pass validation or they don’t. For tests, we can &lt;a href=&quot;https://github.com/andyet/yeti-threads/blob/master/test/index.js#L11-L13&quot;&gt;generate our own JWT&lt;/a&gt; using the &lt;a href=&quot;https://www.npmjs.com/package/jsonwebtoken&quot;&gt;jsonwebtoken&lt;/a&gt; package to test against the API directly&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// test/index.js&lt;/span&gt;
config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jwtKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;crypto&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;randomBytes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;base64&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; token &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; jwt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sign&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;user&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;tester-user&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; scope&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;forum_admin&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jwtKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;expiresInMinutes&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; authorization &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Bearer &apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; token&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next time, we’ll go into managing database migrations using &lt;a href=&quot;http://knexjs.org/&quot;&gt;knex.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://andyet.com/&quot;&gt;&amp;#x26;yet provides consulting&lt;/a&gt; for APIs: architecting, coding, testing, and deploying -- whichever services you need. Feel free to ask me any questions via &lt;a href=&quot;mailto:nathan@andyet.com&quot;&gt;&amp;#x3C;nathan@andyet.com&gt;&lt;/a&gt; or &lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[A microservices case study: Introducing Yeti Threads]]></title><description><![CDATA[Node.js APIs shouldn’t have to involve any guesswork, so I set out to create a case study Node.js microservice API that had all of the rough…]]></description><link>https://blog.andyet.com/2015/09/02/yeti-threads-case-study-pt-1/</link><guid isPermaLink="false">https://blog.andyet.com/2015/09/02/yeti-threads-case-study-pt-1/</guid><pubDate>Wed, 02 Sep 2015 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Node.js APIs shouldn’t have to involve any guesswork, so I set out to create a case study Node.js microservice API that had all of the rough edges smoothed off. It was also a good chance to play with some new Postgres JSON features. Thus, the  &lt;a href=&quot;https://github.com/andyet/yeti-threads&quot;&gt;Yeti Threads API&lt;/a&gt; was born. The Yeti Threads API is a conversation threading forum API. It’s MIT licensed, so feel free to use it to add conversation threading to your applications.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cldup.com/s3fIcU4Zcv.png&quot; alt=&quot;Yeti Threads illustration by Lynn Fisher&quot;&gt;&lt;/p&gt;
&lt;p&gt;Writing APIs in Node.js should be really, really straightforward, even if you’re doing live eventing. You’re probably exposing a REST API that has basic &lt;em&gt;C&lt;/em&gt;reate &lt;em&gt;R&lt;/em&gt;ead &lt;em&gt;U&lt;/em&gt;pdate &lt;em&gt;D&lt;/em&gt;elete handlers that roughly translate to some database calls. You’re probably sending basic updates over a websocket based on the changes to the database. These things are so well established, that several products out there attempt to commoditize these sorts of APIs.&lt;/p&gt;
&lt;p&gt;Let’s talk about tool choice first.&lt;/p&gt;
&lt;h2 id=&quot;tool-choice&quot;&gt;&lt;a href=&quot;#tool-choice&quot; aria-label=&quot;tool choice permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tool Choice&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://jwt.io/&quot;&gt;JSON Web Tokens&lt;/a&gt; because this is a microservice, we’re not providing our own authentication and user management. OpenID Connect is a standard extension on oAuth2 that handles this problem nicely.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://postgresql.org&quot;&gt;Postgresql&lt;/a&gt; is not a new database, but it is getting to be more popular. With new JSON features in 9.4 and 9.5, it brings the best of both worlds in terms of key-stores, document-stores, and SQL querying. Additionally, the new logical replication features provide a basis for much more powerful and flexible scaling.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://hapijs.com/&quot;&gt;hapi&lt;/a&gt; is not the most popular HTTP service for Node.js, that honor belongs to Express, but it provides a much more opinionated and direct approach for writing routes and plugins, as well as having a lot of complimentary libraries that are flexible for use in and outside of hapi.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fritzy/verymodel&quot;&gt;VeryModel&lt;/a&gt; is my go-to library for modeling. It provides a flexible way to manage data-state in a way that can easily transition from a source to export way.&lt;/p&gt;
&lt;p&gt;I wrote &lt;a href=&quot;https://github.com/fritzy/gatepost&quot;&gt;Gatepost&lt;/a&gt; to experiment with the idea of binding queries directly to a model for Postgresql.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fritzy/pgboom&quot;&gt;PGBoom&lt;/a&gt; is a hapi plugin which translates Postgres errors to Boom’s HTTP Errors, so that we didn’t need to write error logic for every handler.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.websocket.org/&quot;&gt;Websockets&lt;/a&gt; have good support these days, and provide a clean way for APIs to give continued updates to client applications. Yeti Threads uses websockets to send notifications relayed from Postgresql’s NOTIFY channels.&lt;/p&gt;
&lt;h2 id=&quot;the-series&quot;&gt;&lt;a href=&quot;#the-series&quot; aria-label=&quot;the series permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Series&lt;/h2&gt;
&lt;p&gt; In follow-up blog posts, we’ll dive into the individual pieces, experiments, and choices of Yeti Threads in order to provide a deep understanding of why and how. If you’d like to get it going, get a free trial of auth0 (or any other OpenID Connect provider) and give it a whirl. I’ll be working on it more during the series, like adding knex.js-based migrations, and possibly breaking out the eventing into an npm module. Pull requests, issues, and critique is welcome!&lt;/p&gt;
&lt;p&gt; &lt;a href=&quot;https://andyet.com/&quot;&gt;&amp;#x26;yet provides consulting&lt;/a&gt; for APIs: architecting, coding, testing, and deploying -- whichever services you need.&lt;/p&gt;
&lt;p&gt; The next part of this series is now up: &lt;a href=&quot;https://blog.andyet.com/2015/09/14/yeti-threads-case-study-auth&quot;&gt;A microservices case study: Auth&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Why &yetConf?]]></title><description><![CDATA[We humans are a funny bunch. By our nature, we’re both creators and consumers. You might even say those are the most basic instincts we act…]]></description><link>https://blog.andyet.com/2015/09/01/why-yetconf/</link><guid isPermaLink="false">https://blog.andyet.com/2015/09/01/why-yetconf/</guid><pubDate>Tue, 01 Sep 2015 14:10:00 GMT</pubDate><content:encoded>&lt;p&gt;We humans are a funny bunch. By our nature, we’re both creators and consumers. You might even say those are the most basic instincts we act on for our survival. But, even though we’re both, when we’re in one role, we tend to do a pretty bad job of considering the other role. To wit, in the capitalist society that most of us live in, many businesses have been built around exploiting our own penchant for consuming for the sake of profit and not necessarily the betterment of the consumer or our society (broadly, “survival”).&lt;/p&gt;
&lt;p&gt;Generally, those businesses are built on the idea that the business can most successfully extract maximum value from a customer by minimizing their costs, and by doing this they’ve met their requirement for existing. &lt;/p&gt;
&lt;p&gt;This can create &lt;strong&gt;some&lt;/strong&gt; success, but what creates long-term sustained success, for both the company and society? We strongly agree with the many people who are much smarter than we are, who say that it’s making a connection with your customer/client/consumer/user.&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet, we fundamentally believe that goods and services can be created in such a way that first and foremost creates a human connection between the person that uses or buys a product or service and the business that created it. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“We make software for human people.”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is precisely what we set out to do with our own products (like &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt;, our software consulting services, and, perhaps most specifically, the product and prototype development we’ve done for our clients over the years.&lt;/p&gt;
&lt;p&gt;We’ve met amazing people at businesses, both huge and tiny, who share that same belief with us. We know there are others like us out there and we know there are more who would feel the same way if they could apply that way of thinking to what they’re doing. We love talking to our friends about these things, we love meeting and talking to new people about these things... so that’s what we’ve decided to make our conference about.&lt;/p&gt;
&lt;p&gt;This year’s &lt;a href=&quot;http://andyetconf.com&quot;&gt;&amp;#x26;yetConf&lt;/a&gt; will be a gathering of old friends and new, an effort to provide excellent conditions and environments for discussing and learning about connecting with people. Our aim is to gather anyone who shares the desire to make our world a better place by creating something, whether through art, technology, food, or something else. &lt;strong&gt;We strongly believe that the most productive conversations we have on this topic are in-person, and this is the essence of why we decided to put on the conference.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To our fellow technologists — no, this is not your typical tech conference. Sure, we could talk about this JavaScript framework or that, WebRTC, realtime messaging architectures, etc. (and maybe some of that will happen!), but &lt;strong&gt;the aim of the conference is not to anoint a technology or tool or methodology as “The Way”.&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;Instead we’ll talk about how you can make a connection with your user. You’ll walk away with extremely valuable context that you can &lt;em&gt;add&lt;/em&gt; to whatever it is you’re doing.&lt;/p&gt;
&lt;p&gt;So. &lt;/p&gt;
&lt;p&gt;Are &lt;strong&gt;you&lt;/strong&gt; creating something you want to be successful? &lt;/p&gt;
&lt;p&gt;Do you want your creation to be loved and talked about by its consumers? &lt;/p&gt;
&lt;p&gt;Do you want the service you provide to stand out? &lt;/p&gt;
&lt;p&gt;We’d love to have you, your team, your family, or anyone else who wants to talk or learn about connecting with people via our creative instincts to come do that with us at &lt;a href=&quot;http://andyetconf.com&quot;&gt;&amp;#x26;yetConf, October 6-8&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Conferences are an art form. Introducing &yetConf’s textcapade: an event preceded by an adventure]]></title><description><![CDATA[Conferences are an art form.I didn’t always believe this, but I certainly have since I started going to exceptionally and intentionally…]]></description><link>https://blog.andyet.com/2015/08/28/conferences-are-an-art-form/</link><guid isPermaLink="false">https://blog.andyet.com/2015/08/28/conferences-are-an-art-form/</guid><pubDate>Fri, 28 Aug 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Conferences are an art form.&lt;/p&gt;
&lt;p&gt;I didn’t always believe this, but I certainly have since I started going to exceptionally and intentionally designed events.&lt;/p&gt;
&lt;p&gt;In an information dense world, connection and meaning are things we hunger for—and those are what the majority of people are &lt;em&gt;really&lt;/em&gt; looking for in a conference.&lt;/p&gt;
&lt;p&gt;It’s not the content. It’s the people. It&apos;s the connections between them and inspiration and personal reflection that the content makes possible. It’s the new direction in their life that attendees choose because of one long conversation in a corner. It’s the idea they are exposed to alongside meeting the person it originated from that sets their future trajectory.&lt;/p&gt;
&lt;p&gt;I have never known anything more inspiring or transformational in my life than great people with whom I resonated.&lt;/p&gt;
&lt;p&gt;And if you want to gather a diverse mix of exceptional people, you must create a unique event. (It also sure as hell better be &lt;a href=&quot;http://andyetconf.com/code-of-conduct/&quot;&gt;safe&lt;/a&gt; and &lt;a href=&quot;https://blog.andyet.com/2015/07/10/the-road-to-diversity-at-andyetconf&quot;&gt;inclusive&lt;/a&gt; of &lt;a href=&quot;https://blog.andyet.com/2015/07/13/announcing-andyetconf-diversity-tickets-and-sponsorships&quot;&gt;all kinds of people&lt;/a&gt;, too.)&lt;/p&gt;
&lt;p&gt;The magic of thinking of a conference as an art form and not an information exchange is how it unlocks the possibility of breaking all the rules. There are no art rules. For the artist, art is about conveying a message or an ideal or a feeling but doing so in a way that’s completely respectful to their counterparts who will interact with it.&lt;/p&gt;
&lt;p&gt;“Music and art have a way of getting inside you without having to be invited.” In that one sentence, an artist I respect named Natalie Closner (of the band &lt;a href=&quot;http://thebandjoseph.com/&quot;&gt;Joseph&lt;/a&gt;) summed up why we do &lt;a href=&quot;http://andyetconf.com&quot;&gt;&amp;#x26;yetConf&lt;/a&gt; the way we do.&lt;/p&gt;
&lt;p&gt;Talking about values in and of themselves is usually boring at best and preachy at worst. And unless people already share your values, it’s like inviting someone to your house for dinner and making them put on your clothes—it’s just weird and uncomfortable.&lt;/p&gt;
&lt;p&gt;There is no more emphatic and inviting way to invoke very real questions about our values than artistic presentation.&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;http://experience.realtimeconf.com&quot;&gt;RealtimeConf 2013&lt;/a&gt;, we created a world and a story and &lt;a href=&quot;http://experience.realtimeconf.com/experience&quot;&gt;experience&lt;/a&gt; that allowed people to interact with real-world tensions and idealistic values in an allegorical world that burst into the conference.&lt;/p&gt;
&lt;p&gt;We’re doing the same this year with &lt;a href=&quot;http://andyetconf.com&quot;&gt;&amp;#x26;yetConf&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Novels are a powerful medium for exploring philosophical perspectives. An author is able to communicate multiple viewpoints about a topic through several characters, and the reader is invited to participate in the discussion, to try on philosophies and play with them.&lt;/p&gt;
&lt;p&gt;I have numerous passages from Fyodor Dostoyevsky&apos;s “The Idiot” and “Brothers Karamazov” underlined—passages that forced me to think about deep topics dear to me like idealism, kindness, faith, morality, and justice. In Nick Harkaway’s “Gone Away World”, I found a series of powerful illustrations which perfectly and dramatically sum up my distrust for organizational hierarchy that removes moral accountability.&lt;/p&gt;
&lt;p&gt;In Mike Speegle’s Kirkus award-winning novel, &lt;a href=&quot;http://experience.realtimeconf.com/novel&quot;&gt;Something Greater than Artifice&lt;/a&gt; (written for RealtimeConf), we were able to address themes like power, centralization, diversity, security, privacy, and broken tech culture and its inhumane values.&lt;/p&gt;
&lt;p&gt;But one element of releasing a novel (and graphic novel) before RealtimeConf was our ability to send it out in advance—to begin the conference well before it actually started.&lt;/p&gt;
&lt;p&gt;As I learned many years ago from my friend &lt;a href=&quot;http://twitter.com/paulca&quot;&gt;Paul Campbell&lt;/a&gt;, one of the most powerful methods for invoking circumstances which connect people is to create shared experiences—particularly effective when they are surprises. They allow people to have something to talk about. They’re a genuine ice-breaker—one so much better than default small talk, which some people are uncomfortable with (myself included). Conference talks &lt;em&gt;can&lt;/em&gt; do this—but not all talks can and not everyone will be interested in discussing them, and often people may feel fearful they’re not good enough or smart enough to discuss them publicly.&lt;/p&gt;
&lt;p&gt;There’s another angle. By the end of most conferences, people usually make a few friends and feel part of a group. But one thing that I’ve learned from my own observations is that for the first half of any conference, there is a level of hesitance and “walls up” feeling from many people, and a question of “Am I part of them? Do I belong?” After about a day, that goes away.&lt;/p&gt;
&lt;p&gt;One of the great things about being able to release a story that leads up to a conference is to be able to create a shared experience not just &lt;em&gt;during&lt;/em&gt; the conference but in advance of it as well. All people walk in with something to excitedly talk about—and they’ve had to endure weeks of eagerly waiting to talk about it.&lt;/p&gt;
&lt;p&gt;But let’s face it: not everyone&apos;s gonna read a novel. (A decent percentage of 2013 attendees did, and the majority did read the graphic novel.) &lt;/p&gt;
&lt;p&gt;But we started thinking: what if we could create an experience that was more interactive? And less “work” than reading a novel?&lt;/p&gt;
&lt;p&gt;Thus was born our first &lt;strong&gt;Textcapade&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Today, &amp;#x26;yetConf attendees will be getting the first of approximately 9 episodes of an interactive text-based choose-your-own-adventure story written by &lt;a href=&quot;http://twitter.com/mike_speegle&quot;&gt;Mike Speegle&lt;/a&gt; that will lead into the rest of the story that will unfold during the conference.&lt;/p&gt;
&lt;p&gt;Each episode takes a total of between 15 and 30 minutes to play, but can be played at whatever pace.&lt;/p&gt;
&lt;p&gt;The amazing &lt;a href=&quot;http://twitter.com/one000mph&quot;&gt;Heather Seaman&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/wraithgar&quot;&gt;Michael Garvin&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/designsaves&quot;&gt;Terry Carter&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/philip_roberts&quot;&gt;Philip Roberts&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/quitlahok&quot;&gt;Nathan LaFreniere&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/codebear&quot;&gt;Bear&lt;/a&gt; are responsible for the hard work on the application that powers the story. If you see them on Twitter, please &lt;a href=&quot;https://twitter.com/intent/tweet?text=@one000mph+@wraithgar+@designsaves+@philip_roberts+@quitlahok+@codebear+Hey,+awesome+work+on+textcapades+for+@andyetconf!&quot;&gt;give the the team props for their hard work&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This experience is sponsored by &lt;a href=&quot;http://tropo.com&quot;&gt;Tropo&lt;/a&gt; and powered by Tropo’s SMS API. We are unbelievably grateful for them believing in us and the vision of this event and helping in a huge way to make it a reality.&lt;/p&gt;
&lt;p&gt;We have a TON more surprises coming as a part of &amp;#x26;yetConf, a diverse set of wonderful artists involved, and some speakers who I can&apos;t wait to hear from.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you haven&apos;t already caught it via other means, &amp;#x26;yetConf is a conference focused on the intersections of technology with humanity, meaning, and ethics.&lt;/em&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If the theme of &amp;#x26;yetConf resonates with you, we’d love to have you involved.&lt;/strong&gt; Tickets are $1399 (they include 3 nights hotel and 7 meals). We also have diversity scholarships available. (And, yes, we’re accepting donations toward diversity scholarships.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://andyetconf.com#tickets&quot;&gt;You can request an &amp;#x26;yetConf ticket here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One last note. So far, all we’ve managed to scrape together is one and only one sponsor. Literally one! We almost can’t even. (Thanks, Tropo!) Obviously, we have room for a lot more and a tons of cool things worth sponsoring.&lt;/p&gt;
&lt;p&gt;If you’re interested in sponsoring &amp;#x26;yetConf, I can guarantee you’ll get your money&apos;s worth. We’ll do much better than put your logo on a website—you’ll be part of a truly unforgettable experience. Reach out to us at &lt;a href=&quot;mailto:conf@andyet.com&quot;&gt;conf@andyet.com&lt;/a&gt; if you’re interested.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Goodbye Henrik!]]></title><description><![CDATA[It is with many yeti tears that we bid a fond farewell to one of our deepest friends, Henrik Joreteg. Henrik has made the difficult choice…]]></description><link>https://blog.andyet.com/2015/08/18/goodbye-henrik/</link><guid isPermaLink="false">https://blog.andyet.com/2015/08/18/goodbye-henrik/</guid><pubDate>Tue, 18 Aug 2015 13:36:00 GMT</pubDate><content:encoded>&lt;p&gt;It is with many yeti tears that we bid a fond farewell to one of our deepest friends, &lt;a href=&quot;https://twitter.com/HenrikJoreteg&quot;&gt;Henrik Joreteg&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://joreteg.com/post/127007507032/the-next-adventure-awaits&quot;&gt;Henrik has made the difficult choice to leave our team&lt;/a&gt; to pursue the many exciting and challenging experiences awaiting him. Although we look forward to working together with Henrik in the future, we will definitely miss hearing his puntastic dadcore jokes in the hallway and hearing the pitter patter of those weird toe shoes he wears. &lt;/p&gt;
&lt;p&gt;All joking aside, while we are saddened to lose such an amazing teammate, we are 1000% behind Henrik pursuing his dreams. Henrik heavily contributed to making us one of the best Node consultancies around, and helped us push our capabilities within the bleeding edge of realtime technologies. He will be greatly missed in the many adventures ahead of our team. &lt;/p&gt;
&lt;p&gt;To Henrik, Heinrich, and even, Roosterick —  we wouldn’t be where we are today without you, and we are deeply grateful for the impact you’ve had on our work, our team, our ideas, and each of us individually. We wish you nothing but the very best in your next chapter. &amp;#x3C;&amp;#x26;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What the Flux?! Let’s Redux.]]></title><description><![CDATA[Every once in a while something new comes along that just feels right. When this happens, I get a tingly feeling in my left pinky toe. That…]]></description><link>https://blog.andyet.com/2015/08/06/what-the-flux-lets-redux/</link><guid isPermaLink="false">https://blog.andyet.com/2015/08/06/what-the-flux-lets-redux/</guid><pubDate>Thu, 06 Aug 2015 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every once in a while something new comes along that just feels right. &lt;/p&gt;
&lt;p&gt;When this happens, I get a tingly feeling in my left pinky toe. That’s how I know it’s not just a fad. It’s how I know it’s legit.&lt;/p&gt;
&lt;p&gt;My pinky toe has a pretty decent track record:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It first tingled when I moved an element on the page with jQuery.&lt;/li&gt;
&lt;li&gt;It tingled when Backbone.js came out. &lt;a href=&quot;https://blog.andyet.com/2010/10/29/building-a-single-page-app-with-backbonejs-undersc&quot;&gt;I blogged about it in 2010&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;It tingled when I pushed my first message from server to client with Socket.io and Node.js &lt;/li&gt;
&lt;li&gt;It tingled with React after I got over “JSX shock”&lt;/li&gt;
&lt;li&gt;It’s been tingling for a few weeks straight now about a thing called Redux. &lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Redux, you say?!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes. As in &lt;a href=&quot;https://twitter.com/dan_abramov&quot;&gt;Dan Abramov’s&lt;/a&gt; Flux-inspired application-state management &lt;a href=&quot;https://github.com/gaearon/redux&quot;&gt;thingamabobber&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s so young! How can you know?! &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yeah, I can’t. It’s so young that it doesn’t even have its own website yet and poor Dan has barely had time to &lt;em&gt;start&lt;/em&gt; &lt;a href=&quot;http://gaearon.github.io/redux/&quot;&gt;writing docs&lt;/a&gt; yet. &lt;/p&gt;
&lt;p&gt;He’s been scrambling to throw together gists showing patterns to those of us who have been trying to build stuff with it. &lt;/p&gt;
&lt;p&gt;Despite all that it’s gathering stars on GitHub like… something that gathers a lot of stars.&lt;/p&gt;
&lt;h2 id=&quot;so-whats-the-big-deal&quot;&gt;&lt;a href=&quot;#so-whats-the-big-deal&quot; aria-label=&quot;so whats the big deal permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So what’s the big deal?&lt;/h2&gt;
&lt;p&gt;Application state in &lt;a href=&quot;https://blog.andyet.com/2015/01/22/native-web-apps&quot;&gt;Native Web Apps&lt;/a&gt; (a.k.a. Single Page Apps) is &lt;em&gt;hard&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When I say “state” I mean not only the data coming from an API, but also all the UI state in an application. It’s state that determines which navigation item is “active”, which view is currently showing, even the current &lt;em&gt;url&lt;/em&gt; is just another piece of state.&lt;/p&gt;
&lt;p&gt;In order to be able to build complex applications we have to have ways of abstracting and dealing with state outside of just putting in the DOM and reading from the DOM.&lt;/p&gt;
&lt;p&gt;What I mean is, if you’ve got code like this anywhere in your app: &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;element&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;active&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// do something        &lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You’re reading state from the DOM.&lt;/p&gt;
&lt;p&gt;It works for simple stuff, but simply doesn’t scale well. &lt;/p&gt;
&lt;p&gt;As your app grows, if you’re storing state in the DOM you’ll likely make a mess.&lt;/p&gt;
&lt;h2 id=&quot;this-is-why-we-have-mvc-right&quot;&gt;&lt;a href=&quot;#this-is-why-we-have-mvc-right&quot; aria-label=&quot;this is why we have mvc right permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;This is why we have MVC, right?&lt;/h2&gt;
&lt;p&gt;Well, yes. But at the point where you can relatively inexpensively &lt;a href=&quot;http://reactjs.com/&quot;&gt;re-render at will&lt;/a&gt;. All of a sudden we need a lot less from our M and C.&lt;/p&gt;
&lt;h2 id=&quot;redux-is-only-concerned-with-state&quot;&gt;&lt;a href=&quot;#redux-is-only-concerned-with-state&quot; aria-label=&quot;redux is only concerned with state permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Redux is only concerned with state&lt;/h2&gt;
&lt;p&gt;It doesn’t help you render stuff, it doesn’t tell you how to do routing, etc. It’s &lt;em&gt;just&lt;/em&gt; about maintaining application state.&lt;/p&gt;
&lt;p&gt;It weighs practically nothing. When I add it as a dependency to an existing app and bundle up the app it only increased the final file size by all of &lt;strong&gt;2k&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;When you consider what it does for you when you adopt its patterns and the code &lt;em&gt;you can remove&lt;/em&gt; as a result, likely it will have end up having a decent net decrease in the file size of your app.&lt;/p&gt;
&lt;h2 id=&quot;abstracting-state&quot;&gt;&lt;a href=&quot;#abstracting-state&quot; aria-label=&quot;abstracting state permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Abstracting state&lt;/h2&gt;
&lt;p&gt;Historically, we’ve dealt with the difficulty of state by trying to model it as a set of observable objects (Models) and observable arrays of those models (Collections). &lt;/p&gt;
&lt;p&gt;This gets us quite a bit further than simply keeping state in the DOM. Now we can track our application state as a tree of observable objects. Our views can listen to changes to various pieces of that state and update the DOM accordingly. &lt;/p&gt;
&lt;p&gt;That’s all fine and good. You can clearly build very complex applications using this pattern.&lt;/p&gt;
&lt;p&gt;I have done that, other people have done that, it’s very doable. &lt;/p&gt;
&lt;p&gt;But… is it enough?&lt;/p&gt;
&lt;h2 id=&quot;maybe-not&quot;&gt;&lt;a href=&quot;#maybe-not&quot; aria-label=&quot;maybe not permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Maybe not.&lt;/h2&gt;
&lt;p&gt;Why not? The short answer is: It’s still very easy to make a mess of your app. &lt;/p&gt;
&lt;p&gt;You’ve got events firing everywhere with unknown side-effects. Pretty soon, it’s hard to trace errors. &lt;/p&gt;
&lt;p&gt;In addition, by introducing all these observable objects we’ve also &lt;strong&gt;dramatically increased the API surface area of the code&lt;/strong&gt;. In other words, there’s &lt;em&gt;so much more&lt;/em&gt; that a developer has to understand before they can work on the app. They have to understand how to observe your models, how they fire events, etc.&lt;/p&gt;
&lt;p&gt;None of these features really exist &lt;em&gt;in JavaScript&lt;/em&gt; itself. So all of a sudden, knowing &lt;em&gt;JavaScript&lt;/em&gt; itself isn’t good enough you also have to have a deep understanding of the observables you’re using.&lt;/p&gt;
&lt;h2 id=&quot;performance&quot;&gt;&lt;a href=&quot;#performance&quot; aria-label=&quot;performance permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Performance&lt;/h2&gt;
&lt;p&gt;Another issue is, adding all this “observability” code also involves adding a bunch of code. We’ve &lt;a href=&quot;https://www.filamentgroup.com/lab/mv-initial-load-times.html&quot;&gt;learned&lt;/a&gt; that large JS payloads come with a potentially severe performance penalty.&lt;/p&gt;
&lt;p&gt;Also, constantly checking whether everything’s changed all the time simply isn’t efficient.&lt;/p&gt;
&lt;p&gt;Plus, creating all the custom objects all the time, isn’t without cost. It takes more processing, it takes more memory.&lt;/p&gt;
&lt;h2 id=&quot;simplest-possible-comparison-in-js&quot;&gt;&lt;a href=&quot;#simplest-possible-comparison-in-js&quot; aria-label=&quot;simplest possible comparison in js permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Simplest possible comparison in JS&lt;/h2&gt;
&lt;p&gt;As it turns out, the simplest/fastest way to check whether an object has changed is to check whether it’s the same object reference or not. &lt;/p&gt;
&lt;p&gt;Instead of doing some sort of &lt;a href=&quot;http://underscorejs.org/#isEqual&quot;&gt;deep comparison of properties&lt;/a&gt; such as:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;object1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; object2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It’d be a lot faster/simpler if we knew that any time an object changed, we replaced it, instead of editing it in place.&lt;/p&gt;
&lt;p&gt;Then our check can be simplified to just this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;object1 &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; object2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s the basic idea of “immutability”. It’s not necessarily that you &lt;em&gt;can’t&lt;/em&gt; change the object (I know I was confused by this). We &lt;em&gt;can&lt;/em&gt; implement enforced immutability with &lt;a href=&quot;https://facebook.github.io/immutable-js/&quot;&gt;tools like Immutable.js&lt;/a&gt;. Or even &lt;a href=&quot;https://facebook.github.io/react/docs/update.html&quot;&gt;React.addons.update&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But you don’t &lt;em&gt;need&lt;/em&gt; tools for it. &lt;/p&gt;
&lt;p&gt;You can just follow the immutability rule: “If you change it, replace it.”&lt;/p&gt;
&lt;p&gt;It’s a bit more arduous in ES5, but with the new features being added to the language, it becomes pretty simple.&lt;/p&gt;
&lt;p&gt;Rather than doing:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    something&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;some value&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// here we’re just editing `obj` in place&lt;/span&gt;
obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;something &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;some other value&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can do it like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    something&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;some value&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// this creates a brand new copy overwriting just that key&lt;/span&gt;
obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; something&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;some other value&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can do the same with arrays of objects, rather than editing them in place:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; myStuff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;henrik&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// push modifies the array defined above&lt;/span&gt;
myStuff&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;js lovin fool&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can replace the array like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; myStuff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;henrik&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

myStuff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;mystuff&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;js lovin fool&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The difference is, now our views can &lt;em&gt;super efficiently&lt;/em&gt; determine if they need to update themselves.&lt;/p&gt;
&lt;p&gt;In React such a method exists:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;shouldComponentUpdate (newProps) {
    return newProps.obj !== this.props.obj
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;ok-so-what&quot;&gt;&lt;a href=&quot;#ok-so-what&quot; aria-label=&quot;ok so what permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ok, so what?&lt;/h2&gt;
&lt;p&gt;Did I mention it’s mostly just a simple implementation of a pattern, that it’s super flexible, that it’s tiny, and that it has a very small API surface to learn. These are a few of my favorite things 🎶.&lt;/p&gt;
&lt;p&gt;In addition, the way it’s structured lends itself very nicely to rendering the first payload on the server to build Universal (a.k.a. Isomorphic) apps. &lt;/p&gt;
&lt;h2 id=&quot;how-is-this-compared-to-flux&quot;&gt;&lt;a href=&quot;#how-is-this-compared-to-flux&quot; aria-label=&quot;how is this compared to flux permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How is this compared to Flux?&lt;/h2&gt;
&lt;p&gt;Flux is just a pattern. I’d say it’s a good one, generally. &lt;/p&gt;
&lt;p&gt;But most Flux implementations I’ve seen don’t get me excited. There’s a ton of new verbiage and concepts but it doesn’t really feel like it makes anything dramatically simpler. &lt;/p&gt;
&lt;p&gt;Redux is definitely &lt;em&gt;inspired&lt;/em&gt; by Flux. But it’s not a pure Flux implementation. Biggest difference is that it uses a &lt;em&gt;single store&lt;/em&gt; that wraps a state object containing all the state for your app. Then instead of writing a bunch of stores, you as a developer write reducers for it…&lt;/p&gt;
&lt;h2 id=&quot;so-how-do-i-actually-use-it&quot;&gt;&lt;a href=&quot;#so-how-do-i-actually-use-it&quot; aria-label=&quot;so how do i actually use it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So how do I actually use it?&lt;/h2&gt;
&lt;p&gt;Things to understand:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Everything&lt;/em&gt; that happens in your app is an “action”. These can be caused by users, browser events, or server events. Doesn’t matter. Everything that changes something in your app does it via an “action”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You have one giant state object that represents &lt;em&gt;all&lt;/em&gt; the state in your app. These are not special Models, or Collections, it’s just friggin’ objects, arrays, and primitives. No magic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You write “reducers” for everything that changes state. Are you familiar with the &lt;code class=&quot;language-text&quot;&gt;[].reduce()&lt;/code&gt; method of an array? If not, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce&quot;&gt;go read this&lt;/a&gt;. But a &lt;code class=&quot;language-text&quot;&gt;reduce&lt;/code&gt; function gets a starting state, the current value and returns the new state. That’s exactly what we want to do in response to actions. We get the starting state, the current action, and we return the new state. &lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;so-what-does-this-all-mean&quot;&gt;&lt;a href=&quot;#so-what-does-this-all-mean&quot; aria-label=&quot;so what does this all mean permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So what does this all mean?&lt;/h2&gt;
&lt;p&gt;Actions are all sequential. &lt;/p&gt;
&lt;p&gt;You can re-produce exact current state of the app at any point, by having the starting state, and re-playing the actions that occurred.&lt;/p&gt;
&lt;p&gt;Your app becomes a starting state and a sequence of actions.&lt;/p&gt;
&lt;p&gt;This means you can do &lt;em&gt;amazing&lt;/em&gt; things like log out all the actions, and then step backwards in time, and replay them however you want.&lt;/p&gt;
&lt;p&gt;Mix that with the ability to “hot-load” or auto-update your (V)iew components &lt;em&gt;and&lt;/em&gt; your reducer functions without re-loading the page, and you have a new and improved kind of magic. The kind that feels like magic because of the power it gives you, but isn’t actually very hard to wrap your head around.&lt;/p&gt;
&lt;p&gt;Also, it’s important to understand that &lt;em&gt;Redux isn’t in any way tied to React&lt;/em&gt;. You can use Redux with whatever view layer you want. It’s a nice conceptual fit with React, but certainly doesn’t require it.&lt;/p&gt;
&lt;h2 id=&quot;so-should-i-drop-everything-and-build-apps-with-redux&quot;&gt;&lt;a href=&quot;#so-should-i-drop-everything-and-build-apps-with-redux&quot; aria-label=&quot;so should i drop everything and build apps with redux permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So should I drop &lt;em&gt;everything&lt;/em&gt; and build apps with Redux?&lt;/h2&gt;
&lt;p&gt;No. Docs are still being written, Dan is desperately trying to get a 1.0 shipped, the devtools will add a lot of value but they’re not very complete at the moment. &lt;/p&gt;
&lt;p&gt;But watch this space! I built and deployed a simple app with it already and… yeah, going to do a lot more of this.&lt;/p&gt;
&lt;p&gt;Basically, for whatever it’s worth, this is me going on record saying &lt;strong&gt;this is going to be a big deal&lt;/strong&gt; and I think this is where the web should go next.&lt;/p&gt;
&lt;p&gt;This is something I’m very excited about and as a rather even-keeled Swedish guy, it takes a lot to get me excited.&lt;/p&gt;
&lt;p&gt;Disagree? I’m on the twitters as &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt;. Explain (kindly) how I’m wrong :)&lt;/p&gt;
&lt;h2 id=&quot;more-info&quot;&gt;&lt;a href=&quot;#more-info&quot; aria-label=&quot;more info permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More info&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=xsSnOQynTHs&quot;&gt;Dan’s awesome introductory talk from React Europe&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;There’s a &lt;a href=&quot;http://www.reactiflux.com/&quot;&gt;#redux channel on the Reactiflux Slack&lt;/a&gt; where you can get help.&lt;/li&gt;
&lt;li&gt;It’s possible to run the Redux devtools &lt;a href=&quot;https://cloudup.com/cKarBThBpZZ&quot;&gt;as a Chrome extension&lt;/a&gt; which is where I think this needs to go, ultimately.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;http://gaearon.github.io/redux/&quot;&gt;in-progress Redux docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The main &lt;a href=&quot;https://github.com/gaearon/redux&quot;&gt;Redux repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://twitter.com/dan_abramov&quot;&gt;Dan Abramov on Twitter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Happy Birthday, Hapi]]></title><description><![CDATA[Today &yet’s favorite Node.js web framework, hapi, turns four years old. We’ve had some great experiences with hapi and are both excited and…]]></description><link>https://blog.andyet.com/2015/08/05/hapi-birthday/</link><guid isPermaLink="false">https://blog.andyet.com/2015/08/05/hapi-birthday/</guid><pubDate>Wed, 05 Aug 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today &amp;#x26;yet’s favorite Node.js web framework, &lt;a href=&quot;http://hapijs.com&quot;&gt;hapi&lt;/a&gt;, turns four years old. We’ve had some great experiences with hapi and are both excited and proud to continue to be a part of the community surrounding it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/eranhammer&quot;&gt;Eran Hammer&lt;/a&gt; started working on what would eventually become hapi in November of 2010 while working for Yahoo on a project named Sled. Sled was shut down almost a year later in August of 2011 and opensourced as &lt;a href=&quot;https://github.com/hueniverse/postmile&quot;&gt;Postmile&lt;/a&gt; which has been one of the primary examples of building a complex application in hapi since day one. &lt;/p&gt;
&lt;p&gt;Later that same month, Eran created the hapi module as a collection of components extracted from Postmile that were used to build on top of Express. The name hapi was chosen as an acronym for HTTP API, but once it was spoken out loud, the connection to &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Ren_%26_Stimpy_Show&quot;&gt;Ren and Stimpy&lt;/a&gt; was made. Eran later presented hapi to Walmart, where the effort was referred to as Blammo. After years of continued development, hapi has grown into its own unique and powerful framework with an outstanding and helpful community. &lt;/p&gt;
&lt;p&gt;&amp;#x26;yet started using hapi over two years ago and quickly became enamored with it. After nearly a year of contributing bug fixes, writing plugins, and being a part of developing the &lt;a href=&quot;http://hapijs.com&quot;&gt;new site&lt;/a&gt;, I was &lt;a href=&quot;https://twitter.com/hapijs/status/442058486134763520&quot;&gt;made a core contributor&lt;/a&gt; in March of 2014. Since then I’ve been super proud to continue helping out the community any way that I’m able.&lt;/p&gt;
&lt;p&gt;If you’re not familiar with hapi, today would be a great day to check it out. Visit &lt;a href=&quot;http://hapijs.com&quot;&gt;the website&lt;/a&gt;, read tutorials, or just make something with it and see how it goes! I’ll personally be available for a large portion of the day in both IRC (#hapi on freenode) and &lt;a href=&quot;https://gitter.im/hapijs/hapi&quot;&gt;Gitter&lt;/a&gt; for any questions/comments/concerns or if you just want to say hi.&lt;/p&gt;
&lt;p&gt;Also, remember if you’re interested in joining the community and helping out with your code skills we’re &lt;a href=&quot;https://github.com/hapijs/contrib/issues/33&quot;&gt;still looking for a few maintainers&lt;/a&gt;. I’d be happy to help anyone who is interested get started.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Selenium, Travis-CI and WebRTC == <&]]></title><description><![CDATA[It’s been a while since I last wrote about testing WebRTC applications. And guess what? There has been some progress. We’re now using Travis…]]></description><link>https://blog.andyet.com/2015/07/28/selenium-travis-webrtc/</link><guid isPermaLink="false">https://blog.andyet.com/2015/07/28/selenium-travis-webrtc/</guid><pubDate>Tue, 28 Jul 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s been a while since I &lt;a href=&quot;https://blog.andyet.com/2014/09/29/testing-webrtc-applications&quot;&gt;last wrote&lt;/a&gt; about testing WebRTC applications. And guess what? There has been some progress. We’re now using Travis-CI for integration tests in combination with Selenium for UI testing.&lt;/p&gt;
&lt;p&gt;The usage of Travis-CI has been &lt;a href=&quot;http://rtc.io/testing-process.html&quot;&gt;described quite a while ago&lt;/a&gt; by our rtc.io friends. It is now being used by &lt;a href=&quot;https://github.com/webrtc/adapter&quot;&gt;adapter.js&lt;/a&gt; which has recently become a dependency of our core modules like &lt;a href=&quot;https://github.com/otalk/getusermedia&quot;&gt;getUserMedia&lt;/a&gt; and &lt;a href=&quot;https://github.com/otalk/rtcpeerconnection&quot;&gt;RTCPeerConnection&lt;/a&gt; since it shims the differences between browsers and is maintained by people from Google and Mozilla.&lt;/p&gt;
&lt;p&gt;What Travis does is run a series of tests on every pull request. Thanks to &lt;a href=&quot;https://github.com/damonoehlman/travis-multirunner&quot;&gt;travis-multirunner&lt;/a&gt; this is running the testsuite (located &lt;a href=&quot;https://github.com/webrtc/adapter/tree/master/test&quot;&gt;here for adapter.js&lt;/a&gt;) in different versions of Chrome and Firefox.
If the tests pass and jshint and jscs don’t find any style nits, there is a nice green badge:&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9ceaa1fc2fe3c789ff1dea72dcb3c2e3/a1792/travis-tests-pass.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 29.13907284768212%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA6UlEQVQY02WPaU7EMAyFe/9jcAdugfiHAAmNYIYkrdMsztI0SwOeIASCT1ZsRXrPz9Pt+UaktxM8C2LhfObKKB+csdpYM96fsqhhXc8CLjOsGqZHc8fjiZlXJbVcJSLmnHvvx+DjH0fvtfV69Nz26ehHrXXP6Z1dAKR3TimltTaDlNI+yN+UAX1se5jIpZarGFaQUgIsQB4ADt22bd6Tm6M4pP+S1VLSnhXGLceJkjzh/cvyMLNFiJkLYGIRnAsuGGMUopH5OORP/mtsajJxHSUtsB61C5q2ebRo0FkaYoohhtJK6+13kfgTUQVVU3CgODkAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;tests passing&quot;
        title=&quot;&quot;
        src=&quot;/static/9ceaa1fc2fe3c789ff1dea72dcb3c2e3/90cbd/travis-tests-pass.png&quot;
        srcset=&quot;/static/9ceaa1fc2fe3c789ff1dea72dcb3c2e3/29fe9/travis-tests-pass.png 151w,
/static/9ceaa1fc2fe3c789ff1dea72dcb3c2e3/6728c/travis-tests-pass.png 303w,
/static/9ceaa1fc2fe3c789ff1dea72dcb3c2e3/90cbd/travis-tests-pass.png 605w,
/static/9ceaa1fc2fe3c789ff1dea72dcb3c2e3/a1792/travis-tests-pass.png 780w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This makes both contributing code as well as merging pull requests easier. No more doubts whether the merge is going to break things. If it does... add a unit test to prevent this in the future. Running the tests in different browser versions also helps detect unexpected API changes before they hit the main release.&lt;/p&gt;
&lt;p&gt;So we have code changes covered by those integration tests and some basic protection against browser vendors breaking our application with updates. Let’s go back to testing a WebRTC application like &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt;. The approach we used became more problematic as we moved from the simple 1-1 and full-mesh videochat to the more advanced architecture that Talky now uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1-1 videochats are still sent between both peers&lt;/li&gt;
&lt;li&gt;for Firefox users we continue to use the “full mesh” approach until the &lt;a href=&quot;https://hacks.mozilla.org/2015/06/firefox-multistream-and-renegotiation-for-jitsi-videobridge/&quot;&gt;multistream support&lt;/a&gt; in Firefox is stable enough&lt;/li&gt;
&lt;li&gt;for Chrome users, we upgrade to a session relayed by our videobridge once a third person joins.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This gets rather complex to test with the old approach of filtering out information from the log files.&lt;/p&gt;
&lt;p&gt;So what if there was a tool that lets you automate browsers... maybe you heard of &lt;a href=&quot;http://www.seleniumhq.org/&quot;&gt;Selenium&lt;/a&gt;? You probably did, but if you tried it a couple of years back you had to write your tests in Java. Ugh. Wouldn’t it be much cooler if you could write your tests in the same language that your code is written in?
Well, it turns out that the JavaScript bindings are now very usable! Which for us means we can write complex tests in a matter of minutes. Here is what the Peer-to-Peer tests look like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;#39;use strict&amp;#39;;
var test = require(&amp;#39;tape&amp;#39;);

// allow `npm run selenium &amp;lt;url&amp;gt;` usage
var baseURL = process.argv.length &amp;gt;= 3 ? process.argv[2] : &amp;#39;https://talky.io&amp;#39;;

// https://code.google.com/p/selenium/wiki/WebDriverJs
var seleniumHelpers = require(&amp;#39;./selenium-lib&amp;#39;);
var webdriver = require(&amp;#39;selenium-webdriver&amp;#39;);

function doJoin(driver, room) {
  return driver.get(baseURL + &amp;#39;/&amp;#39; + room)
  .then(function () {
    return driver.findElement(webdriver.By.id(&amp;#39;join&amp;#39;));
  })
  .then(function (button) {
    return button.click();
  });
}

function testP2P(browserA, browserB, t) {
  var room = &amp;#39;testing_&amp;#39; + Math.floor(Math.random()*100000);

  var userA = seleniumHelpers.buildDriver(browserA);
  doJoin(userA, room);

  var userB = seleniumHelpers.buildDriver(browserB);
  doJoin(userB, room);

  userA.wait(function () {
    return userA.executeScript(&amp;#39;return (function() {&amp;#39; +
      &amp;#39;var sessions = app.xmpp.jingle.sessions;&amp;#39; +
      &amp;#39;var sessionIds = Object.keys(sessions);&amp;#39; +
      &amp;#39;if (sessionIds.length != 2) return false;&amp;#39; +
      &amp;#39;if (sessions[sessionIds[0]].peer.full !== sessions[sessionIds[1]].peer.full) return false;&amp;#39; +
      &amp;#39;return sessions[sessionIds[0]]._connectionState === \&amp;#39;connected\&amp;#39;;&amp;#39; +
      &amp;#39;})()&amp;#39;);
  }, 30*1000)
  .then(function () {
    t.pass(&amp;#39;P2P connected&amp;#39;);
    userA.quit();
    userB.quit().then(function () {
      t.end();
    });
  })
  .then(null, function (err) {
    t.fail(err);
    userA.quit();
    userB.quit();
  });
}

test(&amp;#39;P2P, Chrome-Chrome&amp;#39;, function (t) {
  testP2P(&amp;#39;chrome&amp;#39;, &amp;#39;chrome&amp;#39;, t);
});

test(&amp;#39;P2P, Firefox-Firefox&amp;#39;, function (t) {
  testP2P(&amp;#39;firefox&amp;#39;, &amp;#39;firefox&amp;#39;, t);
});

test(&amp;#39;P2P, Chrome-Firefox&amp;#39;, function (t) {
  testP2P(&amp;#39;chrome&amp;#39;, &amp;#39;firefox&amp;#39;, t);
});

test(&amp;#39;P2P, Firefox-Chrome&amp;#39;, function (t) {
  testP2P(&amp;#39;firefox&amp;#39;, &amp;#39;chrome&amp;#39;, t);
});&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What this test does is rather simple. It creates Selenium drivers (using some special options to get a fake camera, see &lt;a href=&quot;https://github.com/webrtc/samples/blob/master/test/selenium-lib.js&quot;&gt;here&lt;/a&gt;, then joins a Talky room by navigating to a URL and clicking a button and then waits for the second client to join. The executeScript call is executed every 500 milliseconds until the condition (which checks if the P2P connection got established) is true.&lt;/p&gt;
&lt;p&gt;This is done for all combinations of Chrome and Firefox (and maybe soon Microsoft Edge with the &lt;a href=&quot;http://blogs.windows.com/msedgedev/2015/07/23/bringing-automated-testing-to-microsoft-edge-through-webdriver/&quot;&gt;recent addition of a Webdriver&lt;/a&gt;). The next step here is obviously adding different versions of each browser to the test matrix. Wait, we have done that before... with travis-multirunner. Could those two be integrated?&lt;/p&gt;
&lt;p&gt;Turns out this is possible, but it was a little too complicated for me. So I was glad that Google’s Christoffer Jansson
&lt;a href=&quot;https://github.com/webrtc/samples/pull/571&quot;&gt;took my initial work&lt;/a&gt; and connected the dots in the &lt;a href=&quot;https://github.com/webrtc/samples&quot;&gt;WebRTC samples repository&lt;/a&gt;. As a side effect, at least some of those samples are now covered by Selenium tests as well. So if browser updates break the samples, we don’t have to wait for users to report the problem -- which happened just &lt;a href=&quot;https://github.com/webrtc/samples/issues/564&quot;&gt;recently&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And at that point, the lazy developer can just sit back and relax while watching browser windows popping up all over the place:
&lt;img src=&quot;/selenium-samples-a5ad362e8af12def802cb17cc67d6e7f.gif&quot; alt=&quot;selenium doing all the hard work&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Five books to make you a better human and teammate]]></title><description><![CDATA[With the amount of content available for us to consume it's very hard to pick what to dive into. People read at different paces, often times…]]></description><link>https://blog.andyet.com/2015/07/22/five-books-to-make-you-a-better-human-and-teammate/</link><guid isPermaLink="false">https://blog.andyet.com/2015/07/22/five-books-to-make-you-a-better-human-and-teammate/</guid><pubDate>Wed, 22 Jul 2015 11:10:00 GMT</pubDate><content:encoded>&lt;p&gt;With the amount of content available for us to consume it&apos;s very hard to pick what to dive into. People read at different paces, often times not in their native language. At &amp;#x26;yet, we are quite keen on reading too. There are many books that have made us laugh or taught us about design or technology; but only a few truly challenged the way we think and act—some of them to the point of knowing excerpts by heart.&lt;/p&gt;
&lt;p&gt;Today I want to share five publications that shed a light on collaboration, as well as a range of social issues. Each of these books have helped make us better partners, friends and teammates—and above all, better humans.&lt;/p&gt;
&lt;p&gt;Whether you read one or all of them, hopefully they will have the same profound effect on you as well.&lt;/p&gt;
&lt;h2 id=&quot;creativity-inc-overcoming-the-unseen-forces-that-stand-in-the-way-of-true-inspiration&quot;&gt;&lt;a href=&quot;#creativity-inc-overcoming-the-unseen-forces-that-stand-in-the-way-of-true-inspiration&quot; aria-label=&quot;creativity inc overcoming the unseen forces that stand in the way of true inspiration permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Creativity, Inc.: Overcoming the Unseen Forces That Stand in the Way of True Inspiration&quot;&lt;/h2&gt;
&lt;figure class=&apos;image-pull-left&apos;&gt;
  &lt;img src=&apos;/uploads/books-creativity-inc.jpg&apos; width=&apos;150&apos; alt=&apos;Creativity, Inc.&apos; /&gt;
&lt;/figure&gt;
&lt;p&gt;Ed Catmull
&lt;a href=&quot;http://www.amazon.com/Creativity-Inc-Overcoming-Unseen-Inspiration/dp/0812993012&quot;&gt;Amazon&lt;/a&gt;, &lt;a href=&quot;https://itunes.apple.com/us/book/creativity-inc./id733503589?mt=11&quot;&gt;iTunes&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Trust doesn’t mean that you trust that someone won’t screw up—it means you trust them even when they do.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ed Catmull’s memoir holds a special place in our hearts, not only because of our penchant for Pixar and Disney but also for appealing strongly to &lt;em&gt;people first&lt;/em&gt; driven collaboration, which is what &amp;#x26;yet is all about. &lt;em&gt;Creativity, Inc.&lt;/em&gt; emphasises the value of trust and teaches &lt;em&gt;humble, empowering leadership&lt;/em&gt; rather than cultivating more culturally ingrained leader-follower schemes.&lt;/p&gt;
&lt;h2 id=&quot;non-violent-communication-a-language-of-life&quot;&gt;&lt;a href=&quot;#non-violent-communication-a-language-of-life&quot; aria-label=&quot;non violent communication a language of life permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Non-Violent Communication: A Language of Life&quot;&lt;/h2&gt;
&lt;figure class=&apos;image-pull-left&apos;&gt;
  &lt;img src=&apos;/uploads/books-nonviolent.jpg&apos; width=&apos;150&apos; alt=&apos;Non-Violent Communication&apos; /&gt;
&lt;/figure&gt;
&lt;p&gt;Marshall Rosenberg
&lt;a href=&quot;http://www.amazon.com/Nonviolent-Communication-A-Language-Life/dp/1892005034&quot;&gt;Amazon&lt;/a&gt;, &lt;a href=&quot;https://itunes.apple.com/us/book/nonviolent-communication-language/id437014500?mt=11&quot;&gt;iTunes&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I define judgments—both positive and negative—as life-alienating communication.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The role and importance of communication in our lives, let alone work environment, cannot be highlighted enough. In the world of remote culture and text messaging being on a rise, it becomes easier to misunderstand each other and end up in conflict. Rosenberg provides a non-judgemental, honest framework for translating potential negativity into voicing needs.&lt;/p&gt;
&lt;h2 id=&quot;internet-of-garbage&quot;&gt;&lt;a href=&quot;#internet-of-garbage&quot; aria-label=&quot;internet of garbage permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Internet of Garbage&quot;&lt;/h2&gt;
&lt;figure class=&apos;image-pull-left&apos;&gt;
  &lt;img src=&apos;/uploads/books-internet-garbage.jpg&apos; width=&apos;150&apos; alt=&apos;Internet of Garbage&apos; /&gt;
&lt;/figure&gt;
&lt;p&gt;Sarah Jeong
&lt;a href=&quot;http://www.amazon.com/The-Internet-Garbage-Sarah-Jeong-ebook/dp/B011JAV030&quot;&gt;Amazon&lt;/a&gt;, &lt;a href=&quot;https://itunes.apple.com/us/book/the-internet-of-garbage/id1018956157?mt=11&quot;&gt;iTunes&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Community moderation is not just about ex post removal of garbage—it is also about the ex ante dissemination of norms, as well as the collection of information that will best inform engineers on how to build out technical architecture in the future.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Fresh off the press, Jeong’s book dives deep into the darkest corners of The Web, digging through piles of unwanted content. &lt;em&gt;“Internet of Garbage”&lt;/em&gt; not only discusses the boundaries of free speech and its transformation into harassment but also goes through the taxonomy of oppression, offers insight into recognition, prevention and legal repercussions of such. An excellent primer to community moderation.&lt;/p&gt;
&lt;h2 id=&quot;unspeakable-things&quot;&gt;&lt;a href=&quot;#unspeakable-things&quot; aria-label=&quot;unspeakable things permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Unspeakable Things&quot;&lt;/h2&gt;
&lt;figure class=&apos;image-pull-left&apos;&gt;
  &lt;img src=&apos;/uploads/books-unspeakable.jpg&apos; width=&apos;150&apos; alt=&apos;Unspeakable Things&apos; /&gt;
&lt;/figure&gt;
&lt;p&gt;Laurie Penny
&lt;a href=&quot;http://www.amazon.com/Unspeakable-Things-Sex-Lies-Revolution/dp/1620406896&quot;&gt;Amazon&lt;/a&gt;, &lt;a href=&quot;https://itunes.apple.com/us/book/unspeakable-things/id890652097?mt=11&quot;&gt;iTunes&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Feminism has never just been about liberating women from men, but about freeing every human being from the straitjacket of gender oppression.” &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Beware, Laurie Penny isn&apos;t going to butter it up—&lt;em&gt;&quot;Unspeakable Things&quot;&lt;/em&gt; is surely a controversial read, but a much needed one. Penny navigates the dangerous waters of the state of feminism under capitalism and exponentially growing cyberspace. Dissecting the unrealistic cult of beauty surrounding women she also touches on crippling self-doubt haunting men, highlighting the fact that feminism is about freeing all sexes from gender opression.&lt;/p&gt;
&lt;h2 id=&quot;daring-greatly-how-the-courage-to-be-vulnerable-transforms-the-way-we-live-love-parent-and-lead&quot;&gt;&lt;a href=&quot;#daring-greatly-how-the-courage-to-be-vulnerable-transforms-the-way-we-live-love-parent-and-lead&quot; aria-label=&quot;daring greatly how the courage to be vulnerable transforms the way we live love parent and lead permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Daring Greatly: How the Courage to Be Vulnerable Transforms the Way We Live, Love, Parent, and Lead&quot;&lt;/h2&gt;
&lt;figure class=&apos;image-pull-left&apos;&gt;
  &lt;img src=&apos;/uploads/books-daring.jpg&apos; width=&apos;150&apos; alt=&apos;Daring Greatly&apos; /&gt;
&lt;/figure&gt;
&lt;p&gt;Brené Brown
&lt;a href=&quot;http://www.amazon.com/Daring-Greatly-Courage-Vulnerable-Transforms/dp/1592408419&quot;&gt;Amazon&lt;/a&gt;, &lt;a href=&quot;https://itunes.apple.com/us/book/daring-greatly/id512395427?mt=11&quot;&gt;iTunes&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Vulnerability sounds like truth and feels like courage. Truth and courage aren&apos;t always comfortable, but they&apos;re never weakness.” &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You might not be a fan of self-growth related books, but I assure you, this might single-handedly be the best book I have ever read. &lt;em&gt;&quot;Daring Greatly&quot;&lt;/em&gt; is a heart-warming pledge to embrace vulnerability as courage and a way to meaningful life. Brown teaches how to nurture compassion, connection and worthiness. Unlike many self-help books it&apos;s based on years and years of academic researched, thoroughly described in the appendix.&lt;/p&gt;
&lt;p&gt;These books made us rethink not only how to foster creativity, how to communicate effectively and compassionately, but also helped us gain perspective on somewhat controversial topics such as modern feminism and fighting online harassment.&lt;/p&gt;
&lt;p&gt;Happy reading!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Generating CSS Keyframe animations with JavaScript for fun and profit]]></title><description><![CDATA[Yup. You can describe animations in JavaScript and generates CSS strings of  animations and insert them at runtime using  tags. Sounds a bit…]]></description><link>https://blog.andyet.com/2015/07/17/generating-css-keyframe-animations-with-javascript/</link><guid isPermaLink="false">https://blog.andyet.com/2015/07/17/generating-css-keyframe-animations-with-javascript/</guid><pubDate>Fri, 17 Jul 2015 15:29:00 GMT</pubDate><content:encoded>&lt;p&gt;Yup. You can describe animations in JavaScript and generates CSS strings of &lt;code class=&quot;language-text&quot;&gt;@keyframe&lt;/code&gt; animations and insert them at runtime using &lt;code class=&quot;language-text&quot;&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags. &lt;/p&gt;
&lt;p&gt;Sounds a bit wacky right? Why would you do this!?!&lt;/p&gt;
&lt;p&gt;Well... because it’s fun, of course!&lt;/p&gt;
&lt;p&gt;Here’s what I built with these techniques: &lt;a href=&quot;http://dot.surge.sh&quot;&gt;SEE THE DEMO&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We wanted a little menu we could add to any of our static sites, or &lt;a href=&quot;https://andyet.com/opensource&quot;&gt;open source project sites&lt;/a&gt; or wherever, really, just by dropping in a &lt;code class=&quot;language-text&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag. &lt;/p&gt;
&lt;p&gt;I’m not endorsing this technique, per sé, but I think it might have its place for certain problems. Anyway, thought I’d write this up a bit to share what I learned.&lt;/p&gt;
&lt;h2 id=&quot;first-of-all-why&quot;&gt;&lt;a href=&quot;#first-of-all-why&quot; aria-label=&quot;first of all why permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;First of all, why?!&lt;/h2&gt;
&lt;p&gt;It’s generally known that you have two options for animations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Writing CSS Keyframes statically once in your CSS&lt;/li&gt;
&lt;li&gt;Creating an animation loop in JavaScript, typically using &lt;code class=&quot;language-text&quot;&gt;requestAnimationFrame&lt;/code&gt; and calculating values in JS, applying them as &lt;code class=&quot;language-text&quot;&gt;element.style&lt;/code&gt; properties for the duration of your animation.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The CSS Keyframes technique is generally considered to be better performing, because you can offload things to the GPU. Especially if you’re animating CSS properties that are considered &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/speed/high-performance-animations/&quot;&gt;cheap to animate&lt;/a&gt;. But, it has some limitations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You have to know your animation values ahead of time.&lt;/li&gt;
&lt;li&gt;They’re kind of a pain to write, especially without CSS preprocessors that let you do loops, etc. It also requires that you do prefixed versions for ye olde iOS: &lt;code class=&quot;language-text&quot;&gt;-webkit-keyframe&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;They can a bit tricky to control and compose and observe state of these animations. Chris Coyier &lt;a href=&quot;https://css-tricks.com/controlling-css-animations-transitions-javascript/&quot;&gt;wrote a great post about how to do this&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you &lt;em&gt;need&lt;/em&gt; dynamic values &lt;code class=&quot;language-text&quot;&gt;requestAnimationFrame&lt;/code&gt; is the other option. &lt;/p&gt;
&lt;p&gt;This is kind of a pain as well. Because you have to manage the life-cycle of the animation loop, simply leaving it running drains your battery.&lt;/p&gt;
&lt;h3 id=&quot;there-is-actually-a-third-option&quot;&gt;&lt;a href=&quot;#there-is-actually-a-third-option&quot; aria-label=&quot;there is actually a third option permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;There &lt;em&gt;is&lt;/em&gt; actually a third option&lt;/h3&gt;
&lt;p&gt;If we generate CSS keyframe animations with JS, then we get a bit of the benefits of both.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Offload to GPU  &lt;/li&gt;
&lt;li&gt;Describe and get some limited control of animations in JS&lt;/li&gt;
&lt;li&gt;Can create dynamic values&lt;/li&gt;
&lt;li&gt;Doesn’t require running a &lt;code class=&quot;language-text&quot;&gt;requestAnimationFrame&lt;/code&gt; loop.&lt;/li&gt;
&lt;li&gt;Easier to chain and compose&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I Googled a bit and didn’t find anything on npm that really did this and was having fun so I made &lt;a href=&quot;https://github.com/HenrikJoreteg/create-keyframe-animation&quot;&gt;a little library&lt;/a&gt; that lets me do this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; animations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; animations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;create-keyframe-animation&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// this creates the animation above&lt;/span&gt;
animations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;move&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// the actual animation changes&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// these are x, y coordinates&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// there are other alternatives&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// for describing these too.	&lt;/span&gt;
  animation&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now I’ve got an animation named &lt;code class=&quot;language-text&quot;&gt;move&lt;/code&gt; registered and I can run it on any element or elements I want like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; elements &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.dot&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
animations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;runAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;elements&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;move&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running an animation also returns a &lt;code class=&quot;language-text&quot;&gt;Promise&lt;/code&gt; so you can chain them pretty easily:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;animations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;runAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;stop&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; animations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;runAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;drop&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; animations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;runAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;roll&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Done!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;You’ve stopped, dropped, and rolled.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;You’re probably no longer on fire.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
	  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;oww! fire’s hot!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can read more in the &lt;a href=&quot;https://github.com/HenrikJoreteg/create-keyframe-animation&quot;&gt;readme&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;a-few-things-i-learned&quot;&gt;&lt;a href=&quot;#a-few-things-i-learned&quot; aria-label=&quot;a few things i learned permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A few things I learned&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;If you’re running a CSS animation with a single iteration it will jump back to its original position when done unless you set &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode&quot;&gt;animation-fill-mode&lt;/a&gt; to &lt;code class=&quot;language-text&quot;&gt;forwards&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;both&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Removing the &lt;code class=&quot;language-text&quot;&gt;style.animation&lt;/code&gt; property will also revert the element to where it was &lt;em&gt;before&lt;/em&gt; you started the animation. &lt;/li&gt;
&lt;li&gt;Reading the position of an element that has been moved with a &lt;code class=&quot;language-text&quot;&gt;translate&lt;/code&gt; transform can be tricky. In order to do it you have to use &lt;code class=&quot;language-text&quot;&gt;getComputedStyle&lt;/code&gt; and read the &lt;code class=&quot;language-text&quot;&gt;transform&lt;/code&gt; (or &lt;code class=&quot;language-text&quot;&gt;webkitTransform&lt;/code&gt; in safari. But that will give you a transform [matrix] which isn’t super easy to parse/read. I &lt;a href=&quot;https://www.npmjs.com/package/get-css-translated-position&quot;&gt;published a little module&lt;/a&gt; that uses a hacky method to extract the &lt;code class=&quot;language-text&quot;&gt;x&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;y&lt;/code&gt; position of a translated element from that matrix.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;style.transform&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;style.animation&lt;/code&gt; don’t play nicely together. If for example, you’ve got a transform, setting the animation property that animates that same property won’t do anything.&lt;/li&gt;
&lt;li&gt;Prefixes galore. Animation properties and transform properties are all prefixed in Webkit (iOS). Animation and transition end events are also prefixed for iOS. &lt;a href=&quot;https://www.npmjs.com/package/prefixed-event&quot;&gt;This module&lt;/a&gt; can help listen for those.&lt;/li&gt;
&lt;li&gt;If you played with the &lt;a href=&quot;http://dot.surge.sh/&quot;&gt;demo dot&lt;/a&gt; on your phone you may have noticed once you drag the dot you can toss it around and then tilt your phone to move and bounce the dot around with “gravity”. Note that this portion &lt;em&gt;is&lt;/em&gt; done with &lt;code class=&quot;language-text&quot;&gt;requestAnimationFrame&lt;/code&gt; not the CSS technique. But it added a fun element and took surprisingly little code. Many mobile browsers will give you an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/DeviceMotionEvent&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;ondevicemotion&lt;/code&gt; event&lt;/a&gt; that will include &lt;code class=&quot;language-text&quot;&gt;event.accelerationIncludingGravity&lt;/code&gt; which basically does the gravity math for you. I stumbled across &lt;a href=&quot;http://www.albertosarullo.com/blog/javascript-accelerometer-demo-source&quot;&gt;this post&lt;/a&gt; on &lt;a href=&quot;https://twitter.com/albertosarullo&quot;&gt;Alberto Sarullo’s&lt;/a&gt; blog and took &lt;a href=&quot;http://www.albertosarullo.com/demos/accelerometer/&quot;&gt;his awesome 20 LOC demo&lt;/a&gt; switched it to use &lt;code class=&quot;language-text&quot;&gt;requestAnimationFrame&lt;/code&gt; and animating &lt;code class=&quot;language-text&quot;&gt;transform&lt;/code&gt; instead of &lt;code class=&quot;language-text&quot;&gt;top&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;left&lt;/code&gt; and was amazed and how well it worked. Hilariously, I discovered that Android and iOS have differing opinions on which way is up and give inverted values for acceleration. So I needed to do this to teach them which way was up:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;device motion&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// iOS and android do opposite values :-/&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; modifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;/iPad|iPhone|iPod/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userAgent &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
  d&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ax &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accelerationIncludingGravity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; modifier
  d&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ay &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accelerationIncludingGravity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; modifier
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;resources&quot;&gt;&lt;a href=&quot;#resources&quot; aria-label=&quot;resources permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resources&lt;/h2&gt;
&lt;p&gt;After I had already written my little lib, I tweeted this:&lt;/p&gt;
&lt;blockquote class=“twitter-tweet” lang=“en”&gt;&lt;p lang=“en” dir=“ltr”&gt;Dynamically generating CSS keyframe animations with JS in the browser. &amp;#10;&amp;#10;Good idea? Or bad idea?&lt;/p&gt;&amp;mdash; Henrik Joreteg (@HenrikJoreteg) &lt;a href=“https://twitter.com/HenrikJoreteg/status/618231158778671104”&gt;July 7, 2015&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=“//platform.twitter.com/widgets.js” charset=“utf-8”&gt;&lt;/script&gt;
&lt;p&gt;I discovered, unsurprisingly, that I wasn’t the first to try this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/jeremyckahn&quot;&gt;Jeremy Kahn&lt;/a&gt; has &lt;a href=&quot;http://jeremyckahn.github.io/blog/2013/07/28/60-fps-or-bust-dynamically-prerendering-css-animations/&quot;&gt;written about&lt;/a&gt; and used this technique in his &lt;a href=&quot;http://rekapi.com/&quot;&gt;rekapi&lt;/a&gt; animation library.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/amo.js&quot;&gt;amo.js&lt;/a&gt; also uses these techniques, and seems quite cool.&lt;/p&gt;
&lt;p&gt;Other great people to follow who do web animation stuff &lt;a href=&quot;https://twitter.com/greensock&quot;&gt;GreenSock&lt;/a&gt; does amazing things. Check out the &lt;a href=&quot;http://greensock.com/&quot;&gt;GSAP&lt;/a&gt; demos.&lt;/p&gt;
&lt;p&gt;If you’ve seen any of Stripe’s &lt;a href=&quot;https://stripe.com/dashboard/iphone&quot;&gt;sweet UI animations&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/bdc&quot;&gt;Benjamin De Cock&lt;/a&gt; is probably more than partially to blame for that awesomeness. &lt;/p&gt;
&lt;p&gt;If you want to understand the challenges of doing great, fluid animation on the web, check out &lt;a href=&quot;https://www.youtube.com/watch?v=1tavDv5hXpo&quot;&gt;Cheng Lou’s recent talk from React Europe&lt;/a&gt;. He’s built some awesome stuff for doing efficient spring dynamics inside react apps in his &lt;a href=&quot;https://github.com/chenglou/react-motion&quot;&gt;react-motion&lt;/a&gt; lib. Check out &lt;a href=&quot;https://cdn.rawgit.com/chenglou/react-motion/3b5be548cd08630a836562a053576ff91f94b93f/demo1/index.html&quot;&gt;this chat heads demo&lt;/a&gt; or &lt;a href=&quot;https://cdn.rawgit.com/chenglou/react-motion/3b5be548cd08630a836562a053576ff91f94b93f/demo2/index.html&quot;&gt;this one&lt;/a&gt; or &lt;a href=&quot;https://cdn.rawgit.com/chenglou/react-motion/3b5be548cd08630a836562a053576ff91f94b93f/demo4/index.html&quot;&gt;this one&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m also a big fan of &lt;a href=&quot;http://impulse.luster.io/&quot;&gt;Impulse&lt;/a&gt; for simple JS physics simulations (also uses spring dynamics). There are some &lt;a href=&quot;http://impulse.luster.io/examples.html&quot;&gt;really impressive demos&lt;/a&gt; there too.&lt;/p&gt;
&lt;h2 id=&quot;now-what&quot;&gt;&lt;a href=&quot;#now-what&quot; aria-label=&quot;now what permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Now what?&lt;/h2&gt;
&lt;p&gt;I’ve sunk enough time into this idea already and have other things to do :) But I thought I’d share what I learned in case it’s useful to anyone.&lt;/p&gt;
&lt;p&gt;See ya on the interwebz. I’m &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; on twitter. /me waves&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Finally, something Daft Punk can be proud of]]></title><description><![CDATA[Thanks to you, our loyal Talky users, today we’re launching an all-new version that’s better, faster, stronger. (We can’t say harder, better…]]></description><link>https://blog.andyet.com/2015/07/17/finally-daft-punk-can-be-proud/</link><guid isPermaLink="false">https://blog.andyet.com/2015/07/17/finally-daft-punk-can-be-proud/</guid><pubDate>Fri, 17 Jul 2015 11:03:00 GMT</pubDate><content:encoded>&lt;p&gt;Thanks to you, our loyal &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt; users, today we’re launching an all-new version that’s better, faster, stronger. (We can’t say &lt;a href=&quot;https://www.youtube.com/watch?v=gAjR4_CbPpQ&quot;&gt;harder, better, faster, stronger&lt;/a&gt; because actually we’ve been making it easier!)&lt;/p&gt;
&lt;p&gt;Among other things we’ve added a few of the features you’ve requested most, such as in-session text chat so you can share links and other information during a call.&lt;/p&gt;
&lt;p&gt;The big deal, though, is that we’ve upgraded the entire technology behind Talky so that you can meet with 15 or more people, at once. We’ve been using it regularly at &amp;#x26;yet and it’s been great for our weekly full-team hangouts.&lt;/p&gt;
&lt;p&gt;This version has &lt;a href=&quot;https://blog.andyet.com/2015/03/19/introducing-talky-beta&quot;&gt;been in beta&lt;/a&gt; for a few months now and it’s finally ready for prime time. We’ve also released an updated version of the &lt;a href=&quot;https://itunes.apple.com/app/talky-free-video-conferencing/id882057960&quot;&gt;Talky iOS app&lt;/a&gt; that works with the new backend technology so you can join a Talky room on the go from your iPhone or iPad.&lt;/p&gt;
&lt;p&gt;Oh, and the same basic code runs our &lt;a href=&quot;https://about.talky.io/on-prem/&quot;&gt;Talky On-Site&lt;/a&gt; product, too (which is available now).&lt;/p&gt;
&lt;p&gt;But our work is never over, so we’ll keep on making improvements. Try it out and &lt;a href=&quot;mailto:support@talky.io&quot;&gt;send us your feedback&lt;/a&gt; so we know what to focus on next!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Get Talky behind your firewall now!]]></title><description><![CDATA[A few weeks ago we talked about the need for private video chat and the challenges involved with making that a reality in a cloud-based…]]></description><link>https://blog.andyet.com/2015/07/13/get-talky-on-premise-now/</link><guid isPermaLink="false">https://blog.andyet.com/2015/07/13/get-talky-on-premise-now/</guid><pubDate>Mon, 13 Jul 2015 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;A few weeks ago we talked about the need for &lt;a href=&quot;https://blog.andyet.com/2015/06/16/hey-you-get-off-of-the-cloud&quot;&gt;private video chat&lt;/a&gt; and the challenges involved with making that a reality in a cloud-based environment. That’s why we’ve been working hard to build a version of Talky you can run on your company’s network to keep your voice and video traffic safely away from the public Internet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We’re proud to announce that &lt;a href=&quot;https://about.talky.io/on-prem/&quot;&gt;Talky On-Premise&lt;/a&gt; is now available.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/talky-onprem-product-shot.jpg&quot; alt=&quot;Talky On-Premise&quot;&gt;&lt;/p&gt;
&lt;p&gt;Talky On-Premise takes the same ultra-simple experience you’ve come to love for &lt;a href=&quot;https://talky.io&quot;&gt;video chat over the Internet&lt;/a&gt;, and moves it in-house. The installation is almost as easy as using Talky in the first place and the price is surprisingly affordable (as we like to say, the only thing astronomical about Talky is the &lt;a href=&quot;http://talkylander.com&quot;&gt;rocket game, Lander&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://about.talky.io/on-prem/#contact&quot;&gt;Contact us&lt;/a&gt; to get started with Talky On-Premise right away.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Announcing &yetConf diversity tickets and sponsorships]]></title><description><![CDATA[As a part of continuous efforts to make our events as inclusive as possible we are very happy to announce diversity tickets.How will…]]></description><link>https://blog.andyet.com/2015/07/13/announcing-andyetconf-diversity-tickets-and-sponsorships/</link><guid isPermaLink="false">https://blog.andyet.com/2015/07/13/announcing-andyetconf-diversity-tickets-and-sponsorships/</guid><pubDate>Mon, 13 Jul 2015 11:10:00 GMT</pubDate><content:encoded>&lt;p&gt;As a part of &lt;a href=&quot;https://blog.andyet.com/2015/07/10/the-road-to-diversity-at-andyetconf&quot;&gt;continuous efforts&lt;/a&gt; to make our events as inclusive as possible we are very happy to announce &lt;strong&gt;diversity tickets&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-will-diversity-tickets-work&quot;&gt;&lt;a href=&quot;#how-will-diversity-tickets-work&quot; aria-label=&quot;how will diversity tickets work permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How will diversity tickets work?&lt;/h2&gt;
&lt;p&gt;The tickets will work in the form of full conference experience scholarships (&lt;strong&gt;travel excluded&lt;/strong&gt;) and we will be opening the application process in the coming weeks.&lt;/p&gt;
&lt;p&gt;They are targeted towards members of underrepresented groups, which includes, but is not limited to: women, people of colour, LGBTQIA+ people, disabled people, and people facing economic or social hardships, who couldn’t participate otherwise.&lt;/p&gt;
&lt;p&gt;We’re offering the following options to fuel the diversity fund:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;$350&lt;/strong&gt; (25% of a ticket) &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$700&lt;/strong&gt; (50% of a ticket)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$1399&lt;/strong&gt; (100% of a ticket)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://ti.to/&amp;#x26;yet/conf-2015/&quot;&gt;Buy a diversity supporter ticket here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sales are processed, as regular tickets, through &lt;a href=&quot;https://ti.to/&amp;#x26;yet/conf-2015/&quot;&gt;ti.to&lt;/a&gt;. If you have problems with using that platform we can arrange for different methods of payment whenever necessary.&lt;/p&gt;
&lt;h2 id=&quot;im-a-company-can-i-help-too&quot;&gt;&lt;a href=&quot;#im-a-company-can-i-help-too&quot; aria-label=&quot;im a company can i help too permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;I’m a company, can I help too?&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Yes&lt;/em&gt;! While diversity tickets are mostly targeted toward individuals who are willing &lt;em&gt;and&lt;/em&gt; able to provide financial help for underrepresented groups we are aware that organizations of all sorts might have greater capabilities to do so.&lt;/p&gt;
&lt;p&gt;&amp;#x26;yetConf is a not-for-profit event but we put the diversity sponsorships in the front and center of our funding efforts. If your organization shares our beliefs in promoting equality please reach out at &lt;a href=&quot;mailto:conf@andyet.com&quot;&gt;conf@andyet.com&lt;/a&gt; for sponsorship options. These opportunities rely on donating x amount of tickets to the giveaway pool and highlight the patron’s commitment towards diversity.&lt;/p&gt;
&lt;p&gt;Again, don’t hesitate to &lt;a href=&quot;https://twitter.com/andyetconf&quot;&gt;tweet at&lt;/a&gt; or &lt;a href=&quot;mailto:conf@andyet.com&quot;&gt;email us&lt;/a&gt; with any questions.&lt;/p&gt;
&lt;p&gt;We greatly appreciate everyone&apos;s support.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The road to diversity at &yetConf]]></title><description><![CDATA[At &yet we strongly believe that a better world not only starts at an individual level but also requires the effort from all of us. As we…]]></description><link>https://blog.andyet.com/2015/07/10/the-road-to-diversity-at-andyetconf/</link><guid isPermaLink="false">https://blog.andyet.com/2015/07/10/the-road-to-diversity-at-andyetconf/</guid><pubDate>Fri, 10 Jul 2015 11:10:00 GMT</pubDate><content:encoded>&lt;p&gt;At &amp;#x26;yet we strongly believe that a better world not only starts at an individual level but also requires the effort from all of us. As we share not only our work but also process in the &lt;a href=&quot;https://andyet.com/opensource&quot;&gt;open&lt;/a&gt; we’d also like to do so with the diversity strategy we’ve prepared for &lt;a href=&quot;https://andyetconf.com&quot;&gt;&amp;#x26;yetConf&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;code-of-conduct-and-harassment-prevention&quot;&gt;&lt;a href=&quot;#code-of-conduct-and-harassment-prevention&quot; aria-label=&quot;code of conduct and harassment prevention permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Code of Conduct and harassment prevention&lt;/h2&gt;
&lt;p&gt;Apart from focusing on designing an unforgettable experience &lt;strong&gt;our first and foremost responsibility towards everyone is enforcing a safe, entirely harassment-free, inclusive environment&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The presence of a Code of Conduct is fortunately (albeit slowly) becoming a standard for the event industry. At &amp;#x26;yetConf all attendees, speakers and staff are required to familiarize themselves with the Code and follow its rules—that includes the main event as well as fringe happenings and social get-togethers. The contents of the Code of Conduct can be found both at &lt;a href=&quot;http://andyetconf.com/code-of-conduct&quot;&gt;&amp;#x26;yetConf&lt;/a&gt; and &lt;a href=&quot;http://geekfeminism.wikia.com/wiki/Conference_anti-harassment/Policy&quot;&gt;Geek Feminism&lt;/a&gt; sites.&lt;/p&gt;
&lt;p&gt;Aware of &lt;a href=&quot;https://modelviewculture.com/pieces/a-code-of-conduct-is-not-enough&quot;&gt;copy-paste culture&lt;/a&gt; surrounding CoCs the staff will be sufficiently prepared to investigate and act upon possible incidents.&lt;/p&gt;
&lt;h2 id=&quot;gearing-up-on-inclusivity&quot;&gt;&lt;a href=&quot;#gearing-up-on-inclusivity&quot; aria-label=&quot;gearing up on inclusivity permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Gearing up on inclusivity&lt;/h2&gt;
&lt;p&gt;Now more than ever &amp;#x26;yetConf aims to attract the most diverse crowd (speaker and attendee wise) not only in terms of gender, skin color, sexual orientation but also spanning across industries way beyond technology, including artists, educators, writers, and individuals representing a range of backgrounds. We want to challenge the status quo and invite whoever shares the values we believe in to join us. We believe doing so is the only way our values can even be achieved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That effort cannot ever be one-sided&lt;/strong&gt;. Despite voicing our invitation we are actively encouraging participation from underrepresented groups as well as working on implementing several inclusion strategies such as: having &lt;a href=&quot;http://geekfeminism.wikia.com/wiki/Restroom&quot;&gt;gender neutral restroom options&lt;/a&gt;, supplying them with toiletries, providing &lt;a href=&quot;https://adainitiative.org/2013/07/another-way-to-attract-women-to-conferences-photography-policies/&quot;&gt;colour-coded lanyards&lt;/a&gt; symbolising photography consent or lack thereof, and deemphasising alcohol presence amongst others.&lt;/p&gt;
&lt;p&gt;We want you there.&lt;/p&gt;
&lt;h2 id=&quot;ensuring-accessibility&quot;&gt;&lt;a href=&quot;#ensuring-accessibility&quot; aria-label=&quot;ensuring accessibility permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ensuring accessibility&lt;/h2&gt;
&lt;p&gt;We’re committed to providing an equal opportunity of a full conference experience for those suffering from mobility, hearing or visual impairments. Venues will be wheelchair accessible and preferred seating will be reserved. We’re intending on arranging speech-to-text transcription on all the talks as well. (We’d love to get a sponsor for this—&lt;a href=&quot;mailto:conf@andyet.com&quot;&gt;contact us&lt;/a&gt; if you’re interested!)&lt;/p&gt;
&lt;p&gt;Furthermore we aim to cater for all dietary requirements of attendees, additionally offering pay-what-you-want chef-prepared meals for those with more severe digestive issues.&lt;/p&gt;
&lt;p&gt;Families are more than welcome at &amp;#x26;yetConf—apart from a significant others track, we have a family and kids track, and we’ll be making childcare available whenever necessary throughout the event.&lt;/p&gt;
&lt;h2 id=&quot;diversity-scholarship-and-sponsorships&quot;&gt;&lt;a href=&quot;#diversity-scholarship-and-sponsorships&quot; aria-label=&quot;diversity scholarship and sponsorships permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Diversity scholarship and sponsorships&lt;/h2&gt;
&lt;p&gt;Similarly to our friends at &lt;a href=&quot;http://2015.jsconf.eu/diversity-tickets/&quot;&gt;JSConf.eu&lt;/a&gt;, we’ve set up a scholarship program allowing financial contributions towards the diversity ticket pool, offering a wide range of percentage-based backing options (&lt;strong&gt;25%&lt;/strong&gt;, &lt;strong&gt;50%&lt;/strong&gt; and &lt;strong&gt;100%&lt;/strong&gt; of the ticket price) as well as full-fledged sponsorships (we will be announcing further details in just a few days).&lt;/p&gt;
&lt;p&gt;(If your organization would be interested in supporting this effort, please do feel free to &lt;a href=&quot;mailto:conf@andyet.com&quot;&gt;reach out to us&lt;/a&gt; now!)&lt;/p&gt;
&lt;p&gt;These are only a few of the strategies we’ve established in pursuit of running the most inclusive, welcoming and unforgettable event we possibly could. There’s still a lot of work ahead of us. We know we &lt;em&gt;will&lt;/em&gt; make mistakes &lt;em&gt;but&lt;/em&gt; we are pouring our hearts &lt;a href=&quot;http://andyetconf.com/#tickets&quot;&gt;($16.38 value)&lt;/a&gt; into this and more than that—welcoming honest feedback as well.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Welcome, Sally!]]></title><description><![CDATA[We're super excited to announce that we've added a new member to our team! Everyone, meet Sally Mohr!Sally comes to us with a ton of…]]></description><link>https://blog.andyet.com/2015/07/09/welcome-sally/</link><guid isPermaLink="false">https://blog.andyet.com/2015/07/09/welcome-sally/</guid><pubDate>Thu, 09 Jul 2015 13:15:42 GMT</pubDate><content:encoded>&lt;p&gt;We&apos;re super excited to announce that we&apos;ve added a new member to our team! Everyone, meet Sally Mohr!&lt;/p&gt;
&lt;p&gt;Sally comes to us with a ton of experience in the business development and client relationship world. Oh, also? She happens to be an infectious fireball of energy and we&apos;re huge fans!&lt;/p&gt;
&lt;p&gt;Sally&apos;s joining us as our new Director of Business Development. As &amp;#x26;yet has grown and matured, we&apos;ve seen a number of folks take significant roles in our business development activities, which has brought us to where we are, obviously, but we recruited Sally in order to double our ability to focus and put attention on these efforts. The passion and energy Sally has for cultivating and growing relationships between people and communities is remarkable, and exactly what we value across the board here at &amp;#x26;yet, so it made perfect sense to add her to our team!&lt;/p&gt;
&lt;p&gt;Isaac Lewis and Sally will work closely together to develop and strengthen our client relationships, our business development strategies, and our product sales strategies for &lt;a href=&quot;https://requiresafe.com&quot;&gt;requireSafe&lt;/a&gt; and &lt;a href=&quot;https://about.talky.io/on-prem/&quot;&gt;Talky On-Prem&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;We&apos;re so excited about this, so won&apos;t you please &lt;a href=&quot;mailto:contact@andyet.com&quot;&gt;say hi to Sally&lt;/a&gt;?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing &yetConf]]></title><description><![CDATA[Today we are announcing &yetConf, a conference about the intersections of technology with humanity, meaning, and ethics for people who…]]></description><link>https://blog.andyet.com/2015/07/07/introducing-andyetconf/</link><guid isPermaLink="false">https://blog.andyet.com/2015/07/07/introducing-andyetconf/</guid><pubDate>Tue, 07 Jul 2015 13:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Today we are announcing &lt;a href=&quot;http://andyetconf.com&quot;&gt;&amp;#x26;yetConf&lt;/a&gt;, a conference about the intersections of technology with humanity, meaning, and ethics for people who believe the world should be better and are determined to make it so.&lt;/p&gt;
&lt;p&gt;In 2013, we presented the most ambitious thing we&apos;ve ever made: RealtimeConf. You can see &lt;a href=&quot;http://experience.realtimeconf.com/experience&quot;&gt;the timeline of RealtimeConf experience outlined here&lt;/a&gt;. That event featured a &lt;a href=&quot;http://experience.realtimeconf.com/novel&quot;&gt;novel&lt;/a&gt; by &lt;a href=&quot;http://twitter.com/mike_speegle&quot;&gt;Mike Speegle&lt;/a&gt; that went on to win a Kirkus Indie Book of the Year award that led into a play that ran through the conference with &lt;a href=&quot;http://experience.realtimeconf.com/music&quot;&gt;original soundtrack&lt;/a&gt; by &lt;a href=&quot;http://twitter.com/obensource&quot;&gt;Ben Michel&lt;/a&gt; and a &lt;a href=&quot;https://alanahenderson.bandcamp.com/track/legacy&quot;&gt;spellbinding original theme song&lt;/a&gt; by &lt;a href=&quot;http://twitter.com/lanihendy&quot;&gt;Alana Henderson&lt;/a&gt;. Oh, and there were a bunch of amazing presentations. And it all took place in a world we&apos;d been slowly creating since the first RealtimeConf—one that left people saying things like, &lt;em&gt;“All my expectations we&apos;re blown away. Wasn&apos;t expecting the level of artistry. Unbelievable, over the top and amazing.”&lt;/em&gt; (&lt;a href=&quot;http://twitter.com/nexxylove&quot;&gt;Emily &quot;Nexxy&quot; Rose&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;As we&apos;ve pursued bringing back RealtimeConf for 2015 and worked hard on some of the ridiculous creative things we have in store, the more we really felt constrained by the name. We really want to make something greater than RealtimeConf in all elements, and we don&apos;t want to be held back. Ultimately, we see conferences as a unique art form and we want to create an event unrestrained in its expression. &lt;/p&gt;
&lt;p&gt;And so, we&apos;d like to introduce &lt;a href=&quot;http://andyetconf.com&quot;&gt;&amp;#x26;yetConf&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;#x26;yetConf isn&apos;t about us—it&apos;s about what &amp;#x26;yet is about—the things we care about, believe in, and aspire to be.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Over the years, we&apos;ve met many people whose visions and values we resonate with and who make us want to be better versions of ourselves. We want to bring those people together, along with the people who we don&apos;t know yet but can&apos;t wait to be inspired by, from all kinds of different backgrounds.&lt;/p&gt;
&lt;p&gt;&quot;Realtime&quot; represents such a tiny part of what we care about and want to discuss. It&apos;s not good enough. It&apos;s not wide enough. It&apos;s not why enough. The entire thesis of RealtimeConf 2013 was well stated by Alana Henderson&apos;s anthem:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If we&apos;re making this world smaller bit by bit,&lt;/em&gt;
&lt;em&gt;what good is that if we&apos;re not all together in it?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If we&apos;re going to bring together some of the most inspiring people we know, why limit that to just technologists? The web is not just about web developers and as a company we&apos;re not obsessed with technology for technology&apos;s sake.&lt;/p&gt;
&lt;p&gt;&amp;#x26;yetConf is a nontechnical technical conference, and an extremely personal event. This is unashamedly the heart of our team and the community of people we love—front and center.&lt;/p&gt;
&lt;p&gt;We want to ask: what are the concerns and hopes of a society based on the technology of today and tomorrow? As we build the future, what lessons can we learn from the past? What things might we choose to do better—or differently—this time?&lt;/p&gt;
&lt;p&gt;We&apos;d love to tell you about the ridiculous details we have planned already for &amp;#x26;yetConf, but we&apos;d probably have to kill you. (Or at least subtweet.)&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&quot;https://docs.google.com/forms/d/1lpFqfb-aUWpkNh3wZmlV33AnqQUCOtXy0Ab33sYadPY/viewform&quot;&gt;request a ticket right now by answering some questions&lt;/a&gt; or visit &lt;a href=&quot;http://andyetconf.com&quot;&gt;andyetconf.com&lt;/a&gt; to learn more about the event. &lt;/p&gt;
&lt;p&gt;This is going to be one of the most special things we have ever been part of making and we really hope that you&apos;ll join us.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;faq&quot;&gt;&lt;a href=&quot;#faq&quot; aria-label=&quot;faq permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;FAQ&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Will it still involve the fictional world created at RealtimeConf&lt;/strong&gt;
Yes, the world created as a part of RealtimeConf will absolutely live on in this event.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What about my presentation submission?&lt;/strong&gt;
Our theme for RealtimeConf was strongly in line with the direction we&apos;re going with &amp;#x26;yetConf, so thankfully a lot of the presentations we got are amazingly fitting for what we&apos;re hoping for. However—they were very tech-centric, and we&apos;ll be looking to diversify the perspectives involved as presenters. So: stay tuned! You&apos;ll hear back from us in a couple weeks if you&apos;re waiting to get a confirmation on your submission.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The last 30 days]]></title><description><![CDATA[two robots saying thank youThe Kickstarter for our video chat service Talky has come to a close. Unfortunately we didn't reach our goal, but…]]></description><link>https://blog.andyet.com/2015/06/26/kickstarter-ended/</link><guid isPermaLink="false">https://blog.andyet.com/2015/06/26/kickstarter-ended/</guid><pubDate>Fri, 26 Jun 2015 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/talky-kickstarter-thankyou-header.png&quot; alt=&quot;two robots saying thank you&quot;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.kickstarter.com/projects/talky/talky-the-first-truly-simple-video-chat/dashboard&quot;&gt;Kickstarter&lt;/a&gt; for our video chat service &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt; has come to a close. Unfortunately we didn&apos;t reach our goal, but realistically this was a truth we faced at the very beginning of this project. &lt;/p&gt;
&lt;p&gt;What we didn&apos;t gain in funding we earned in observation and good ole fashioned market research.  And we&apos;ve learned a lot!&lt;/p&gt;
&lt;p&gt;First, we have an &lt;strong&gt;amazing and supportive community&lt;/strong&gt; who truly loves Talky and wants to see us succeed in our endeavors. Thank you so much if you shared our project, tweeted about it, sent it to folks, commented on it, reached out to us about it — you are the reason we put our hearts into our products the way we do. Thank you.&lt;/p&gt;
&lt;p&gt;Another major takeaway is that we have an audience for &lt;strong&gt;some of Talky&apos;s services, but not all.&lt;/strong&gt; This is a harder truth to face because of all of the work we&apos;ve put into something we care about and believe in. This project made it clear what people want from Talky and what&apos;s maybe not as thrilling of a prospect. The good thing is, at least we know where to head with Talky now.&lt;/p&gt;
&lt;p&gt;Armed with data, and another draft of our roadmap, we&apos;re setting out to chart a new course for the many things to come for Talky.&lt;/p&gt;
&lt;p&gt;If you would like to support Talky in a financial way, we are adding a tip jar to our site. So &lt;a href=&quot;https://andyet.com/kickstarter&quot;&gt;if you enjoy your Talky experience and want to say thank you in that way, now you can&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Once again, from the whole Talky team and all of us at &amp;#x26;yet, thanks for believing in what we do, and pledging your support for Talky. We &amp;#x3C;&amp;#x26; you!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to give great feedback]]></title><description><![CDATA[At &yet we often talk about our design and development process as being highly iterative. To iterate, as we all know, means to do something…]]></description><link>https://blog.andyet.com/2015/06/25/how-to-give-great-feedback/</link><guid isPermaLink="false">https://blog.andyet.com/2015/06/25/how-to-give-great-feedback/</guid><pubDate>Thu, 25 Jun 2015 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At &amp;#x26;yet we often talk about our design and development process as being highly iterative. To iterate, as we all know, means to do something repeatedly. But doing something once, then again, then again, and again, doesn’t singularly ensure that the project is moving in the right direction. It’s the rounds of feedback, sandwiched between iterations, that ultimately dictate the quality of the product.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The thing about feedback is, when given effectively, it is literally the only thing getting you from shitty first draft to shipping a truly quality product.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-first-step-is-asking-for-help&quot;&gt;&lt;a href=&quot;#the-first-step-is-asking-for-help&quot; aria-label=&quot;the first step is asking for help permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The first step is asking for help&lt;/h2&gt;
&lt;p&gt;Before we talk about giving great feedback, it’s important to mention that feedback is made valuable not only by those who give feedback, but by those who seek it as well. Most often, rounds of feedback happen when someone on the team says, “Hey team, look at this thing I’m making. Help me make it better.” &lt;/p&gt;
&lt;p&gt;But it can be amazingly hard, especially in the early phases of a project, when things feel so rough and incomplete, to lay your work on a table, expose it to your team, and look at it under harsh light. It can be easy to feel the compulsion to polish the work &lt;em&gt;that&lt;/em&gt; much more before you share it. Especially in the early phases of design and development, discussion should be largely conceptual, big-picture decisions. But at this phase, feedback is &lt;em&gt;especially&lt;/em&gt; necessary, as it gets you moving in the right direction as early as possible. Just put it out there. Trust me, your team understands. And their feedback will be invaluable.&lt;/p&gt;
&lt;h2 id=&quot;feedback-is-powerful&quot;&gt;&lt;a href=&quot;#feedback-is-powerful&quot; aria-label=&quot;feedback is powerful permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Feedback is powerful&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;The tricky thing about feedback is that it’s powerful. And with great power comes great responsibility...as we all know.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;While feedback cycles have the power to help guide good beginnings into a great product, it’s also possible to shift course in the wrong direction. I’d like to think the most seasoned designers and developers have excellent intuition when it comes to feedback, but it certainly doesn&apos;t hurt to look at feedback as something deeper and more complex than sheer intuition.&lt;/p&gt;
&lt;h4 id=&quot;what-good-feedback-is&quot;&gt;&lt;a href=&quot;#what-good-feedback-is&quot; aria-label=&quot;what good feedback is permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What good feedback is&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;In context –&lt;/strong&gt; This may seem obvious, but it is quite important, and therefore worth pointing out. Good feedback bears in mind all contextual information. This can be everything from user information, size, format and medium, to how users encounter the item being discussed, to maintainability and clarity of code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Often, a question –&lt;/strong&gt; Questions are a valuable part of the feedback process. Whether you are seeking to understand context, or simply inquiring of the designer or developer’s intentions, it’s always productive to ask.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Empowering –&lt;/strong&gt; Honesty doesn’t have to be brutal. Feedback that is honest, but also empowering, acknowledges the intention and choices that the designer or developer has made, reaffirms the established goals, and often includes ideas or guidance on how to better achieve them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Specific –&lt;/strong&gt; It’s easy to say that something just ‘isn&apos;t right.’ Having the vocabulary to identify and explain the friction points is invaluable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Actionable –&lt;/strong&gt; A good feedback session should leave the designer or developer with a clear plan of action to move the project in the right direction. It reaffirms goals and offers very specific guidance on how to better achieve them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paced correctly –&lt;/strong&gt; Sometimes you need quick feedback, and sometimes feedback cycles span over weeks and months. Choosing the right tools and processes (or lack thereof) can hugely influence the quality of feedback and efficiency of the project.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;what-good-feedback-isnt&quot;&gt;&lt;a href=&quot;#what-good-feedback-isnt&quot; aria-label=&quot;what good feedback isnt permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What good feedback isn’t&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Opinion –&lt;/strong&gt; You may be thinking, “Isn’t most feedback someone’s opinion?” Well yes. But, no. Your own opinion can be informed by solid design and programming principles, so after a while they can feel intertwined, but choices should never be suggested simply because you personally prefer one method over another. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Absolute –&lt;/strong&gt; Feedback is about discussion and the give and take of ideas. No piece of individual feedback can ever be perceived as a complete and perfect solution.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A product of groupthink –&lt;/strong&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Groupthink&quot;&gt;Groupthink&lt;/a&gt; is an interesting phenomenon in that it tends to affect very cohesive teams. It reveals that people tend to subconsciously stifle their own beliefs in order to active consensus among a group. Is your feedback based on the desire to gain approval from the team, or does it reflect your honest response?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Personal –&lt;/strong&gt; Don&apos;t focus on the person seeking feedback. Focus on the project&apos;s collective objectives. Feedback is about collaboration, not criticism.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;useful-feedback-tools-for-a-distributed-team&quot;&gt;&lt;a href=&quot;#useful-feedback-tools-for-a-distributed-team&quot; aria-label=&quot;useful feedback tools for a distributed team permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Useful feedback tools for a distributed team&lt;/h2&gt;
&lt;p&gt;There are many applications that promise to offer an easy and streamlined method of curating iterations and feedback. This is a tricky one because tools can be burdensome and impose undue process on an already process-heavy task. When choosing tools to facilitate feedback for our team, it’s important to ensure that feedback be documented, if necessary, and easily accessed by everyone involved. But we also recognize that projects move fast and the relevancy of feedback expires quickly, so the need to archive feedback discussions beyond several days, in most cases, isn’t important.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; –&lt;/strong&gt; Talky is great because it enables you to have a face-to-face video conversation with anyone, anywhere, anytime. It’s hard to get around the fact that commenting on someone’s work can elicit an emotional response at times. Being able to have meaningful feedback conversations face-to-face is invaluable - and made totally simple with Talky.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://slack.com/&quot;&gt;Slack&lt;/a&gt; –&lt;/strong&gt; Where Talky is used more for in-depth conversation, we tend to use Slack for more casual feedback. “Can I get your thoughts on this real quick?”-type stuff. Being able to seek quick smell checks and +1s here and there is a totally valid way to move projects forward efficiently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; –&lt;/strong&gt; GitHub issues are the natural choice for code feedback and UI feedback that is at the implementation stage of design. The ability to use markdown to create a task list with checkmarks is especially handy in giving actionable feedback.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.dropbox.com/&quot;&gt;Dropbox&lt;/a&gt; comments –&lt;/strong&gt; &lt;a href=&quot;http://www.wired.com/2015/04/dropbox-makes-file-sharing-social-comments/&quot;&gt;Dropbox commenting&lt;/a&gt; is the least ephemeral of the design feedback methods we use. Comments in Dropbox live with a file for the duration of its life, and are especially useful for projects that involve longer, more drawn-out feedback cycles in which people drop in and out of the conversation over long periods of time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;go-forth-and-empower&quot;&gt;&lt;a href=&quot;#go-forth-and-empower&quot; aria-label=&quot;go forth and empower permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Go forth and empower&lt;/h2&gt;
&lt;p&gt;Whether it be a formal session, or a quick exchange of ideas, feedback is a hugely important aspect of working as a team. And when you really think about it, to some degree, a large percentage of the communication between team members can be qualified as feedback. It has the power to empower a team to ship great products.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Microsoft Edge support for the WebRTC samples]]></title><description><![CDATA[tl;dr download the Windows 10 preview and test the WebRTC getUserMedia samples in the Microsoft Edge browser!The WebRTC samples that are…]]></description><link>https://blog.andyet.com/2015/06/25/webrtc-on-the-edge/</link><guid isPermaLink="false">https://blog.andyet.com/2015/06/25/webrtc-on-the-edge/</guid><pubDate>Thu, 25 Jun 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; download the Windows 10 preview and test the &lt;a href=&quot;https://webrtc.github.io/samples/src/content/getusermedia/gum/&quot;&gt;WebRTC getUserMedia samples&lt;/a&gt; in the Microsoft Edge browser!&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://webrtc.github.io/samples/&quot;&gt;WebRTC samples&lt;/a&gt; that are made available by Google&apos;s WebRTC team on &lt;a href=&quot;https://github.com/webrtc/samples&quot;&gt;GitHub&lt;/a&gt; are a tremendously useful resource for starting with WebRTC. They are so useful that this year my favorite answer on the &lt;a href=&quot;https://groups.google.com/forum/#!forum/discuss-webrtc&quot;&gt;discuss-webrtc mailing list&lt;/a&gt; has been &quot;there is a sample for that&quot;. &lt;/p&gt;
&lt;p&gt;The samples are grouped into three categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;getUserMedia&lt;/em&gt; samples which show how to use the &lt;a href=&quot;http://w3c.github.io/mediacapture-main/&quot;&gt;getUserMedia API&lt;/a&gt; to access the microphone and camera,&lt;/li&gt;
&lt;li&gt;&lt;em&gt;RTCPeerConnection&lt;/em&gt; samples which demonstrate the use of the &lt;a href=&quot;http://w3c.github.io/webrtc-pc/&quot;&gt;RTCPeerConnection API&lt;/a&gt; to establish a peer-to-peer connection (usually within a single page), and&lt;/li&gt;
&lt;li&gt;&lt;em&gt;RTCDataChannel&lt;/em&gt; samples which demonstrate the higher-level data channel API to send and receive data and files.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The demos make use of &lt;a href=&quot;https://github.com/webrtc/adapter&quot;&gt;&lt;em&gt;adapter.js&lt;/em&gt;&lt;/a&gt; to hide all of the current implementation differences from the developer. The aim is to allow developers to write spec-compliant code that works in any browser. For example, the getUserMedia API is currently available as &lt;code class=&quot;language-text&quot;&gt;navigator.webkitGetUserMedia&lt;/code&gt; in Chrome and &lt;code class=&quot;language-text&quot;&gt;navigator.mozGetUserMedia&lt;/code&gt; in Firefox. Also, Jan-Ivar Bruaroey from Mozilla added some code which transforms the &lt;a href=&quot;https://github.com/webrtc/samples/blob/master/src/content/getusermedia/resolution/js/main.js#L36-L50&quot;&gt;new spec-compliant syntax&lt;/a&gt; to acquire camera resolutions to the &lt;a href=&quot;https://webrtchacks.com/video-constraints-2/&quot;&gt;older syntax&lt;/a&gt; still used by Chrome.&lt;/p&gt;
&lt;p&gt;Last month, the Microsoft Edge team &lt;a href=&quot;https://blogs.windows.com/msedgedev/2015/05/13/announcing-media-capture-functionality-in-microsoft-edge/&quot;&gt;announced support for getUserMedia&lt;/a&gt; in their browser. Wouldn&apos;t it be awesome if the getUserMedia demos would work in Edge, too?&lt;/p&gt;
&lt;p&gt;Since Edge does not use prefixes, there was little to be shimmed. The only difference that needed to be supported was implementing a way to attach media streams to &lt;code class=&quot;language-text&quot;&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements. This is done with the helper function &lt;code class=&quot;language-text&quot;&gt;attachMediaStream()&lt;/code&gt;. Getting &lt;a href=&quot;https://github.com/webrtc/adapter/pull/44&quot;&gt;those changes&lt;/a&gt; added to adapter.js was pretty easy, along with a &lt;a href=&quot;https://github.com/webrtc/adapter/pull/45&quot;&gt;bugfix&lt;/a&gt; resulting from a pull request on one of the Microsoft Edge demos.&lt;/p&gt;
&lt;p&gt;With those changes merged, I attempted to make the samples work with Edge. The biggest problem was that none of the getUserMedia samples actually used adapter.js -- they were designed to be simple and self-explanatory. But now, using adapter.js instead of trying to shim just the required bits in each demo made more sense. This did not take long actually and there were just &lt;a href=&quot;https://github.com/webrtc/samples/pull/517&quot;&gt;a few lines of code&lt;/a&gt; that needed to be changed.&lt;/p&gt;
&lt;p&gt;As a result, all getUserMedia demos work in Edge now as well. And Firefox. And Chrome. Without changes. That&apos;s pretty significant.&lt;/p&gt;
&lt;p&gt;Thanks to Bernard Aboba, Harald Alvestrand, Jan-Ivar Bruaroey and Shijun Sun for helping with these changes.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Harnessing the magic of Hapi scopes]]></title><description><![CDATA[A fantastic, but often underused, feature of hapi is the ability to use scopes for authorization. In many frameworks in order to specify who…]]></description><link>https://blog.andyet.com/2015/06/16/harnessing-hapi-scopes/</link><guid isPermaLink="false">https://blog.andyet.com/2015/06/16/harnessing-hapi-scopes/</guid><pubDate>Tue, 16 Jun 2015 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A fantastic, but often underused, feature of &lt;a href=&quot;http://hapijs.com&quot;&gt;hapi&lt;/a&gt; is the ability to use scopes for authorization. &lt;/p&gt;
&lt;p&gt;In many frameworks in order to specify who has access to what resources, you have to perform manual checks within your route handlers. This can be a hassle since often these checks will be performed in many different routes. Sure, we can abstract them into a plugin or middleware, but with hapi we don’t have to since it’s all built right in. &lt;/p&gt;
&lt;p&gt;Want to specify a route that only admins can access? It’s as simple as configuring it like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    method&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/something/adminy&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    config&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function-variable function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Hello there, admin.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        auth&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            scope&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;admin&apos;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The “scope” field here tells hapi to check your authenticated user’s credentials for the given “admin” scope. If your user’s credential object looks something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;jabba&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;scope&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;admin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hutt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then the user will be authorized and will receive the “Hello there, admin.” message. However, if your user’s credential object lacked the “admin” scope, hapi would automatically reply with a 403 status code.&lt;/p&gt;
&lt;p&gt;This is fantastic for static scopes, things like “admin” or “superuser,” but what if you need to know if a resource belongs to the user making the request? Well, good news. Recently, we got a &lt;a href=&quot;https://github.com/hapijs/hapi/pull/2532&quot;&gt;pull request&lt;/a&gt; merged into hapi to allow the use of dynamic authorization scopes.&lt;/p&gt;
&lt;p&gt;With this new feature, when a user authenticates you can pre-fetch a list of resources that belong to the user and add them to their scope. So let’s say you now have a user with a credentials object that looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;username&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;han&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;scope&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;door-trash-compactor&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Where “door-trash-compactor” is a dynamically generated scope representing the resource type (in this case, “door”) and “trash-compactor” represents the resource’s id. Now we can set up a new route to leverage our fancy new scope:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    method&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    route&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/doors/{door_id}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    config&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function-variable function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;door_id &lt;span class=&quot;token string&quot;&gt;&apos; door is closed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        auth&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            scope&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;door-{params.door_id}&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That magical little &lt;code class=&quot;language-text&quot;&gt;{params.door_id}&lt;/code&gt; part of the scope will be automatically expanded when hapi checks the scope to match the given request. So now if Han Solo were to make a request to &lt;code class=&quot;language-text&quot;&gt;/doors/trash-compactor&lt;/code&gt; the scope would expand to &lt;code class=&quot;language-text&quot;&gt;door-trash-compactor&lt;/code&gt; which is contained in Han’s credentials and he’ll receive the response “trash-compactor door is closed.” Neat, huh?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Hey, you, get off of the cloud!]]></title><description><![CDATA[Talky Kickstarter is live  One of our goals with Talky is to make the service itself and its underlying components as secure as possible…]]></description><link>https://blog.andyet.com/2015/06/16/hey-you-get-off-of-the-cloud/</link><guid isPermaLink="false">https://blog.andyet.com/2015/06/16/hey-you-get-off-of-the-cloud/</guid><pubDate>Tue, 16 Jun 2015 13:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;br&gt;
&lt;img src=&quot;https://blog.andyet.com/uploads/talky-kickstarter-lauch-header-02.png&quot; alt=&quot;Talky Kickstarter is live&quot;&gt;  &lt;/p&gt;
&lt;p&gt;One of our goals with &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; is to make the service itself and its underlying components as secure as possible. For example, as Bear &lt;a href=&quot;https://blog.andyet.com/2015/06/04/talky-security&quot;&gt;explained recently&lt;/a&gt;, we use a variety of industry-standard encryption techniques, including strong cipher suites to enable &lt;a href=&quot;https://en.wikipedia.org/wiki/Perfect_forward_secrecy&quot;&gt;Perfect Forward Secrecy&lt;/a&gt; whenever possible.&lt;/p&gt;
&lt;p&gt;Unfortunately, encrypting video conferences end-to-end with more than a few people is difficult. The challenge is that in peer-to-peer, “full-mesh” mode, your laptop or tablet or mobile phone needs to encode and encrypt one outbound video stream for each person involved. This works well for one-to-one video, but even the most modern computing devices simply can’t encode that much video data if you have more than a few people in the session.&lt;/p&gt;
&lt;p&gt;To overcome that challenge, a service like Talky needs to use a server in the middle (e.g., the &lt;a href=&quot;https://jitsi.org/Projects/JitsiVideobridge&quot;&gt;Jitsi Videobridge&lt;/a&gt;) that accepts one incoming video stream and fans it out to all the other participants. Unfortunately, this kind of &lt;a href=&quot;https://webrtcglossary.com/sfu/&quot;&gt;Selective Forwarding Unit&lt;/a&gt; has to decrypt the video streams that it receives in order to do its job.&lt;/p&gt;
&lt;p&gt;We don’t like that any more than you do. And we’re involved with &lt;a href=&quot;http://www.ietf.org/mail-archive/web/dispatch/current/msg05919.html&quot;&gt;nascent efforts&lt;/a&gt; at the &lt;a href=&quot;https://www.ietf.org/&quot;&gt;Internet Engineering Task Force&lt;/a&gt; to come up with standardized solutions. But it will take a while before those efforts bear fruit, because it’s a hard problem.&lt;/p&gt;
&lt;p&gt;In the meantime, what’s a more private and secure alternative? One approach our customers like is to run their own private installation of Talky behind the firewall so that their conversations never leak outside the company network. Although that doesn’t fully encrypt conversations with external parties like vendors and partners at other companies, it’s a big step in the right direction for internal discussions.&lt;/p&gt;
&lt;p&gt;To make this possible, you need to use a technology that can actually be run on your own network. That’s simply not an option with most video chat services on the market today because they’re built to run in the cloud and only in the cloud.&lt;/p&gt;
&lt;p&gt;By contrast, we’ve put a lot of work into on-premise video chat. Led by &lt;a href=&quot;https://andyet.com/team/marcus&quot;&gt;Marcus&lt;/a&gt; and &lt;a href=&quot;https://andyet.com/team/bear&quot;&gt;Bear&lt;/a&gt; on our operations team, we have created beautifully containerized versions of Talky that will run quite happily with &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt; or &lt;a href=&quot;https://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt; on the hardware of your choice.&lt;/p&gt;
&lt;p&gt;This means you can run an entire Talky instance - signaling, messaging, audio, and video - on your own network, thus keeping all your conversations safely in house. We’re even working to make our Talky &lt;a href=&quot;https://itunes.apple.com/app/talky-free-video-conferencing/id882057960&quot;&gt;iOS app&lt;/a&gt; compatible with this more private and secure option for on-site video conferencing.&lt;/p&gt;
&lt;p&gt;Want to learn more? &lt;a href=&quot;https://andyet.com/talky&quot;&gt;Drop us a line&lt;/a&gt; and let us know how we can help! And don’t forget our &lt;a href=&quot;https://www.kickstarter.com/projects/talky/talky-the-first-truly-simple-video-chat/description&quot;&gt;Kickstarter campaign&lt;/a&gt;, too, which has privacy and security as some of its key goals.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Henrik's upcoming Frontend Masters workshop]]></title><description><![CDATA[We’re excited that one of our yetis, Henrik Joreteg will be teaching a Frontend Masters workshop on June 25-26 on Building Modern Single…]]></description><link>https://blog.andyet.com/2015/06/11/henriks-upcoming-frontend-masters-workshop/</link><guid isPermaLink="false">https://blog.andyet.com/2015/06/11/henriks-upcoming-frontend-masters-workshop/</guid><pubDate>Thu, 11 Jun 2015 13:30:00 GMT</pubDate><content:encoded>&lt;p&gt;We’re excited that one of our yetis, &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;Henrik Joreteg&lt;/a&gt; will be teaching a &lt;a href=&quot;https://frontendmasters.com/&quot;&gt;Frontend Masters&lt;/a&gt; workshop on June 25-26 on &lt;a href=&quot;https://frontendmasters.com/workshops/web-apps/&quot;&gt;Building Modern Single-Page Web Applications&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can attend either online or in-person.&lt;/p&gt;
&lt;p&gt;Here’s Henrik’s description of what he’ll cover in the workshop, but more imporantly, why: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Even the final feature set of the app you’re working on right now is probably a bit vague -- the future of the apps we build and the tools we use is vague at best. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The only thing we can bet on with any certainty is change. Yet so many of frontend developers are going “all-in” on a framework and hoping it will solve all their problems. Even JS itself is going through some major revisions right now with ES6. Even that &lt;em&gt;new&lt;/em&gt; name “ES6” didn’t last long, it’s already been changed to ES2015.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;So, what do we do? Blindly hop on the most promising looking hype train? &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Rather than learning how to use the solutions, let’s understand the relevant problems we’re presented with on the frontend and let’s learn how to solve them. That’s the goal of this workshop. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Yes, we’re going to build an app using some buzzwords like React, ES6 (or whatever you want to call it), Ampersand.js, npm, and webpack. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;But this isn’t about hyping up tools, it’s about building and shipping apps. After all, that’s what we’re here for right?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you’re interested &lt;a href=&quot;https://frontendmasters.com/workshops/web-apps/&quot;&gt;learn more and sign up here&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What exactly is being open sourced from Talky in this Kickstarter?]]></title><description><![CDATA[Talky Kickstarter is livePaul Irish dropped us a line about our Talky Kickstarter and asked:Can you detail the open source plans? What parts…]]></description><link>https://blog.andyet.com/2015/06/09/what-is-being-open-sourced-from-talky/</link><guid isPermaLink="false">https://blog.andyet.com/2015/06/09/what-is-being-open-sourced-from-talky/</guid><pubDate>Tue, 09 Jun 2015 13:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/talky-kickstarter-lauch-header-02.png&quot; alt=&quot;Talky Kickstarter is live&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://twitter.com/paul_irish&quot;&gt;Paul Irish&lt;/a&gt; dropped us a line about our &lt;a href=&quot;https://www.kickstarter.com/projects/talky/talky-the-first-truly-simple-video-chat&quot;&gt;Talky Kickstarter&lt;/a&gt; and asked:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Can you detail the open source plans? What parts of Talky are not open sourced right now, but will be from this kickstarter? What parts of Talky will not be released as open source components?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For starters, let’s be clear that &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt; is not a simple turnkey open source project. It’s too powerful for that, and we want to put that power in developers’ hands.&lt;/p&gt;
&lt;p&gt;The average user doesn’t need or want to run the kind of server infrastructure required to run Talky, and doing so is a nontrivial exercise. The value, we feel, is contributing the components so that people &lt;em&gt;can&lt;/em&gt; make great and ambitious things with it, and so we can empower non-WebRTC developers to have access to these technologies.&lt;/p&gt;
&lt;p&gt;Paul is correct in his underlying assumption that a high percentage of Talky is presently open sourced, but some of these are poorly documented so we kind of consider it only partially open sourced at the present. Open source is kind of our whole thing, so the reality is there’s not a lot we’ve ever held back.&lt;/p&gt;
&lt;p&gt;As an app and service, Talky is highly modular, and we are open sourcing all these module libraries. These modules would be more than sufficient coverage for the hard parts of someone to build a video chat application complete with an XMPP based text chat and using the &lt;a href=&quot;https://jitsi.org/Projects/JitsiVideobridge&quot;&gt;Jitsi Video Bridge&lt;/a&gt; as a WebRTC SFU for multiparty.&lt;/p&gt;
&lt;p&gt;Though we don’t call them this, let’s discuss Talky “1” &lt;a href=&quot;https://talky.io&quot;&gt;(talky.io)&lt;/a&gt; vs Talky “2” &lt;a href=&quot;https://beta.talky.io&quot;&gt;(beta.talky.io)&lt;/a&gt; for context.&lt;/p&gt;
&lt;p&gt;The modules involved in Talky 2 are mostly found at github.com/otalk. Note this is significantly more than the core components of Talky 1, which is primarily &lt;a href=&quot;https://github.com/henrikjoreteg/simplewebrtc&quot;&gt;github.com/henrikjoreteg/simplewebrtc&lt;/a&gt; and related modules. &lt;/p&gt;
&lt;p&gt;Talky 1 is “full mesh” (everyone streams to everyone) while Talky 2 uses a Selective Forwarding Unit (SFU), as Hangouts does, dramatically reducing the individual bandwidth. Talky 1 uses a simple Node server for signaling &lt;a href=&quot;https://github.com/andyet/signalmaster&quot;&gt;(github.com/andyet/signalmaster)&lt;/a&gt; while Talky 2 signaling uses &lt;a href=&quot;https://github.com/otalk/jingle.js&quot;&gt;Jingle&lt;/a&gt; (also like Hangouts) and XMPP, and all of its command-and-control is managed this way. Several of these components are already open sourced, but are not well documented.&lt;/p&gt;
&lt;p&gt;Talky 1 uses &lt;a href=&quot;https://simplewebrtc.com&quot;&gt;SimpleWebRTC&lt;/a&gt;, but Talky 2 does not—yet. Our intent is to bring some of the power we’ve created in &lt;a href=&quot;https://github.com/otalk&quot;&gt;github.com/otalk&lt;/a&gt; back to SimpleWebRTC.&lt;/p&gt;
&lt;p&gt;While there are numerous open source abstraction libraries for basic WebRTC calls, we are unaware of anyone who has open sourced the necessary components to modularly build something like Talky.&lt;/p&gt;
&lt;p&gt;There is also &lt;a href=&quot;http://meet.jit.si&quot;&gt;Jitsi Meet&lt;/a&gt;, an open source project which can be spun up as a standalone open source Hangouts clone. Jitsi Meet was originally authored by our lead WebRTC developer, &lt;a href=&quot;http://twitter.com/hcornflower&quot;&gt;Philipp Hancke&lt;/a&gt;, but he’s proud of the modular JS approach taken with what we’ve open sourced from Talky, thanks to him being able to team up with our veteran JS devs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So—tl;dr: The only pieces we are not open-sourcing are the UI, glue code, and operationalized infrastructure—but that’s it!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For more visit &lt;a href=&quot;https://talky.io&quot;&gt;Talky.io&lt;/a&gt; and &lt;a href=&quot;https://www.kickstarter.com/projects/talky/talky-the-first-truly-simple-video-chat/description&quot;&gt;check out the details of our Kickstarter to take our video chat service to the next level.&lt;/a&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Safety tips for Talky users]]></title><description><![CDATA[One of the greatest lessons we can learn from watching internet platforms and applications grow in popularity is how crucial users' safety…]]></description><link>https://blog.andyet.com/2015/06/05/talky-safety/</link><guid isPermaLink="false">https://blog.andyet.com/2015/06/05/talky-safety/</guid><pubDate>Fri, 05 Jun 2015 13:30:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the greatest lessons we can learn from watching internet platforms and applications grow in popularity is how crucial users&apos; safety can be in utilizing those services. The safety of our Talky users is extremely important to us. &lt;/p&gt;
&lt;p&gt;In keeping with discussing the security and privacy of our service, we also want to share our best practices for safety when using Talky. Below are some tips you can use to help ensure that you have great conversations with the people you choose, and avoid stumbling upon explicit, unwanted content.&lt;/p&gt;
&lt;h2 id=&quot;tip-1---dont-share-talky-rooms-publicly&quot;&gt;&lt;a href=&quot;#tip-1---dont-share-talky-rooms-publicly&quot; aria-label=&quot;tip 1   dont share talky rooms publicly permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tip #1 - Don’t share Talky rooms publicly&lt;/h2&gt;
&lt;p&gt;By default all rooms within Talky are public. When two or more people land on the same link they will be connected with video and audio streaming to each other. Sharing a link to a Talky room via Twitter or Facebook is essentially inviting everyone else. To avoid having an Internet party with strangers, only share links via direct messages or other private methods of communication.&lt;/p&gt;
&lt;h2 id=&quot;tip-2---use-randomly-generated-room-names&quot;&gt;&lt;a href=&quot;#tip-2---use-randomly-generated-room-names&quot; aria-label=&quot;tip 2   use randomly generated room names permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tip #2 - Use randomly generated room names&lt;/h2&gt;
&lt;p&gt;Talky conveniently provides randomly generated and clever room names.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.andyet.com/images/talky-safety-room-name.png&quot; alt=&quot;example of suggested room name&quot;&gt;&lt;/p&gt;
&lt;p&gt;Avoiding common room names greatly decreases your chances of landing on somebody else’s conversation or have somebody else join yours.&lt;/p&gt;
&lt;h2 id=&quot;tip-3---use-locked-rooms&quot;&gt;&lt;a href=&quot;#tip-3---use-locked-rooms&quot; aria-label=&quot;tip 3   use locked rooms permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tip #3 - Use locked rooms&lt;/h2&gt;
&lt;p&gt;By far the best way to get the most protection from having unwanted visitors to your room, Talky allows users to lock a room.&lt;/p&gt;
&lt;p&gt;You can lock the room simply by clicking on the lock button.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.andyet.com/images/talky-safety-lock-room-1.png&quot; alt=&quot;lock button&quot;&gt;&lt;/p&gt;
&lt;p&gt;You’ll be prompted to provide a pass phrase. Remember to treat this like a normal password: the longer the better and only share it using private channels.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.andyet.com/images/talky-safety-set-key.png&quot; alt=&quot;prompt to set a key for a room&quot;&gt;&lt;/p&gt;
&lt;p&gt;A room will show that it has been successfully locked when you have the lock icon displays as being locked.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.andyet.com/images/talky-safety-lock-room-2.png&quot; alt=&quot;unlock button&quot;&gt;&lt;/p&gt;
&lt;p&gt;Users joining the room from then on will be required to enter a key to proceed to join the call.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.andyet.com/images/talky-safety-need-key.png&quot; alt=&quot;prompt for a key to a locked room&quot;&gt;&lt;/p&gt;
&lt;p&gt;We believe in promoting a safe and secure environment for the Talky community. If you have feedback to help us do more we’d &lt;a href=&quot;mailto:support@talky.io&quot;&gt;love to hear from you&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Want to know more about Talky? Visit &lt;a href=&quot;https://talky.io&quot;&gt;Talky.io&lt;/a&gt; and try it out or check out our &lt;a href=&quot;https://www.kickstarter.com/projects/talky/talky-the-first-truly-simple-video-chat&quot;&gt;Kickstarter to take our video chat service to the next level&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Is Talky truly secure?]]></title><description><![CDATA[Talky Kickstarter is liveAt &yet, we take privacy and security seriously. We even have a dedicated security team (Lift Security) that…]]></description><link>https://blog.andyet.com/2015/06/04/talky-security/</link><guid isPermaLink="false">https://blog.andyet.com/2015/06/04/talky-security/</guid><pubDate>Thu, 04 Jun 2015 15:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/talky-kickstarter-lauch-header-02.png&quot; alt=&quot;Talky Kickstarter is live&quot;&gt;&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet, we take privacy and security seriously. We even have a dedicated security team (&lt;a href=&quot;https://liftsecurity.io/&quot;&gt;Lift Security&lt;/a&gt;) that performs security audits for many well-known companies.&lt;/p&gt;
&lt;p&gt;Talky security is more than just making sure the “lock” icon is present in your browser’s tab for your &lt;a href=&quot;https://talky.io&quot;&gt;Talky.io&lt;/a&gt; session. It involves that, but also the connection between your browser and other people in the session, which can be direct (for one-to-one calls) or through the &lt;a href=&quot;https://jitsi.org/Projects/JitsiVideobridge&quot;&gt;Jitsi Videobridge&lt;/a&gt; (for multi-party calls). Another aspect of security is what we do with any information gathered during the session, such as logging and log storage.&lt;/p&gt;
&lt;p&gt;To answer these questions we need to examine the two primary ways Talky is used—making a one-to-one call with someone else or making a many-to-many call.&lt;/p&gt;
&lt;p&gt;Both the one-to-one and many-to-many call types first require you connect with your browser to the Talky.io website. This connection is protected using industry-standard &lt;a href=&quot;https://en.wikipedia.org/wiki/Transport_Layer_Security&quot;&gt;Transport Layer Security (TLS)&lt;/a&gt;. During this connection we record your IP address and your browser’s UserAgent (e.g., Chrome or Mozilla). This information is logged to disk and stored for a maximum of 7 days.&lt;/p&gt;
&lt;p&gt;After you connect to the website, your browser downloads JavaScript code for the Talky application.  If you decide to join a session on the “hair check” page, your browser then uses &lt;a href=&quot;http://xmpp.org/&quot;&gt;XMPP (Extensible Messaging and Presence Protocol)&lt;/a&gt; for “command-and-control” purposes. This XMPP connection is also fully encrypted using TLS. &lt;/p&gt;
&lt;p&gt;Most of the features we support in Talky use standard XMPP extensions for things like call signaling or exchanging messages. There are a few things we do that aren’t yet standardized, but we’re working to standardize them through the &lt;a href=&quot;http://xmpp.org/&quot;&gt;XSF (XMPP Standards Foundation)&lt;/a&gt;. All of the data transferred is fully auditable by checking the network console, as the protocol is fully documented.&lt;/p&gt;
&lt;p&gt;When the second person joins the Talky room, the signaling information from both sessions is shared via the XMPP connection. The respective browsers will then make a WebRTC connection using &lt;a href=&quot;https://en.wikipedia.org/wiki/Perfect_forward_secrecy&quot;&gt;Perfect Forward Secrecy&lt;/a&gt; if supported (which it is both in Chrome and Firefox). If the browsers are unable to make a direct connection for voice and video because of NATs and firewalls, then a relay TURN server will be used. All connections established via the TURN server are encrypted during transit and the data retained in memory only.&lt;/p&gt;
&lt;p&gt;If no other people join the room then the Talky session is &lt;strong&gt;end-to-end encrypted with zero information about the voice and video data being stored or logged&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If any other person connects to an active Talky session, then the other sessions in that room will receive an event via their XMPP connection that the room is changing to a many-to-many session and the client will start connect to the Jitsi Videobridge that we run. We use a media bridge in the multi-party case so your browser doesn’t need to encode video streams to every other participant (which uses a lot of bandwidth and CPU, and therefore doesn’t scale up very well).&lt;/p&gt;
&lt;p&gt;Each browser now connects to an assigned Jitsi Videobridge using a variant of TLS called &lt;a href=&quot;https://en.wikipedia.org/wiki/Datagram_Transport_Layer_Security&quot;&gt;DTLS (Datagram Transport Layer Security)&lt;/a&gt;. In order to do its job, the bridge needs to decrypt the voice and video data sent to it. However, the encryption keys are not persisted to disk and are only available in memory. We also do not log or store any session data on the media bridge server—the voice and video data is decrypted only in memory.&lt;/p&gt;
&lt;p&gt;Please be aware if you are connecting to Talky.io using one of the mobile clients &lt;em&gt;and&lt;/em&gt; have enabled the sending of Crash Reports, some of the data will be stored and accessible by the mobile vendor as the Crash Reports are stored on the vendor’s system.&lt;/p&gt;
&lt;p&gt;More details are available in the Talky &lt;a href=&quot;https://talky.io/help/security&quot;&gt;privacy and security policy&lt;/a&gt;. And, as always, &lt;a href=&quot;mailto:support@talky.io&quot;&gt;let us know&lt;/a&gt; if you have questions about Talky or any other &amp;#x26;yet service.&lt;/p&gt;
&lt;p&gt;Want to know more about Talky? Visit &lt;a href=&quot;https://talky.io&quot;&gt;Talky.io&lt;/a&gt; and &lt;a href=&quot;https://www.kickstarter.com/projects/talky/talky-the-first-truly-simple-video-chat/description&quot;&gt;check out our Kickstarter to take our video chat service to the next level.&lt;/a&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Early bird tickets to RealtimeConf go on sale Tuesday]]></title><description><![CDATA[Next week, on Tuesday, June 2 at 10am PDT, ticket sales for RealtimeConf 2015 will officially begin! Early bird tickets for $1299 will go on…]]></description><link>https://blog.andyet.com/2015/05/28/early-bird-tickets/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/28/early-bird-tickets/</guid><pubDate>Thu, 28 May 2015 13:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Next week, on Tuesday, June 2 at 10am PDT, ticket sales for &lt;a href=&quot;https://realtimeconf.com&quot;&gt;RealtimeConf 2015&lt;/a&gt; will officially begin! &lt;a href=&quot;https://ti.to/&amp;#x26;yet/realtimeconf-2015&quot;&gt;Early bird tickets for $1299 will go on sale.&lt;/a&gt; &lt;/p&gt;
&lt;h2 id=&quot;whats-included&quot;&gt;&lt;a href=&quot;#whats-included&quot; aria-label=&quot;whats included permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What’s included&lt;/h2&gt;
&lt;p&gt;Tickets cover the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;admission to each day of the event&lt;/li&gt;
&lt;li&gt;three nights of accommodations&lt;/li&gt;
&lt;li&gt;six meals&lt;/li&gt;
&lt;li&gt;and a wall-to-wall experience starting when you arrive into town, so you don’t have to worry about logistics and can spend your time enjoying the conference and spare time activities&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tickets will be released in small batches and &lt;strong&gt;will sell out&lt;/strong&gt;, so punctuality is key. &lt;/p&gt;
&lt;h2 id=&quot;significant-other-track&quot;&gt;&lt;a href=&quot;#significant-other-track&quot; aria-label=&quot;significant other track permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Significant Other Track&lt;/h2&gt;
&lt;p&gt;Also available this year are &lt;strong&gt;Significant Other track&lt;/strong&gt; tickets (&lt;strong&gt;$50&lt;/strong&gt;) for a variety of hosted tour options including, but not limited to, experiencing local coffee shops, hiking trails and wineries. We will be announcing details for all activities during upcoming weeks.&lt;/p&gt;
&lt;h2 id=&quot;dietary-restrictions&quot;&gt;&lt;a href=&quot;#dietary-restrictions&quot; aria-label=&quot;dietary restrictions permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Dietary Restrictions&lt;/h2&gt;
&lt;p&gt;We’re very aware of challenges connected to catering to attendees with distinct dietary needs, which is why this year we’re introducing a paid option (&lt;strong&gt;$99&lt;/strong&gt;) to have a culinary specialist arranging and overseeing your meals. Vegetarian, vegan, gluten free, kosher, halal, food allergy—whatever your special dietary needs are, we want to make this experience a great one!&lt;/p&gt;
&lt;p&gt;We’re committed to making RealtimeConf as inclusive event as it could be—if this additional cost creates a hardship for you, please talk to us and we can work to find another way to make your meals comfortable and enjoyable.&lt;/p&gt;
&lt;p&gt;Early bird tickets, along with the Significant Other track and dietary needs tickets, &lt;a href=&quot;https://ti.to/&amp;#x26;yet/realtimeconf-2015&quot;&gt;go on sale promptly at 10am PDT so mark your calendars for June 2&lt;/a&gt;! &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Navigator Office Hours: Frontend Development]]></title><description><![CDATA[We’re continuing our series of Navigator Office Hours—next Thursday, June 4, I’ll be hosting a session focused on frontend development…]]></description><link>https://blog.andyet.com/2015/05/28/karolina-office-hours/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/28/karolina-office-hours/</guid><pubDate>Thu, 28 May 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’re continuing our series of &lt;a href=&quot;https://seaworthy.io/#services&quot;&gt;Navigator Office Hours&lt;/a&gt;—next Thursday, June 4, I’ll be hosting a session focused on frontend development, design and community-related issues.&lt;/p&gt;
&lt;p&gt;You might have heard me chat about technology at &lt;a href=&quot;http://shoptalkshow.com/episodes/131-karolina-szczur/&quot;&gt;Shop Talk Show&lt;/a&gt; or recently on &lt;a href=&quot;http://thestart.fm/interviews/the-fortuneteller&quot;&gt;The Start.fm&lt;/a&gt;—this time we’re going to concentrate on frontend architecture; style guides, maintainability, all things HTML/CSS as well as topics circling around tech community in general, from running diverse events to enhancing team collaboration.&lt;/p&gt;
&lt;p&gt;You can sign up &lt;a href=&quot;https://ti.to/seaworthy/navigator-office-hours-with-karolina-szczur&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Talky doesn’t reinvent the wheel, you won’t believe how!]]></title><description><![CDATA[Talky is &yet’s premier plugin-less, just a link in a browser, group video and chat service. To add to the list of adjectives, we can also…]]></description><link>https://blog.andyet.com/2015/05/27/talky-doesnt-reinvent-the-wheel/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/27/talky-doesnt-reinvent-the-wheel/</guid><pubDate>Wed, 27 May 2015 15:30:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://beta.talky.io&quot;&gt;Talky&lt;/a&gt; is &amp;#x26;yet’s premier plugin-less, just a link in a browser, group video and chat service. To add to the list of adjectives, we can also claim open standards-based, but not by inventing new ones. &lt;/p&gt;
&lt;p&gt;So many services claim to be open, but roll their own API and call it open because they published a document; we didn’t do that. Our team has been contributing to real open standards for decades before we were even a team -- that’s part of why we recruited them.&lt;/p&gt;
&lt;p&gt;Starting with WebRTC, the browser feature that allows us to do video, audio directly between browsers without a plugin, we get the core functionality of Talky, however not the intelligence of it. WebRTC wisely doesn’t include a means of signaling (connecting the call), so we’re left to “roll our own.” On the surface, this is pretty easy -- just set up a server that exchanges the WebRTC signaling payloads between the two browsers and let it go peer-to-peer -- but this is a very naive approach, and ends up being difficult to add features to, maintain, secure, and scale in the long run.&lt;/p&gt;
&lt;p&gt;Did you know that group management, call signaling, presence, chat, federation, and all of those other features you might want to add later have been done before? Not only that, but these features have been painstakingly reviewed and iterated to ensure security, feature-extensions, and interoperability by large communities of professionals, and then documented as &lt;a href=&quot;http://en.wikipedia.org/wiki/Request_for_Comments&quot;&gt;RFCs&lt;/a&gt; and &lt;a href=&quot;http://xmpp.org/xmpp-protocols/xmpp-extensions/&quot;&gt;XEPs&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Additionally, the open source community (and proprietary vendors) have made hundreds of implementations of these standards, proven in a variety of tools and products. I’m talking about &lt;a href=&quot;https://xmpp.org/xmpp-protocols/&quot;&gt;XMPP&lt;/a&gt;, the Internet standard for federated communication.&lt;/p&gt;
&lt;p&gt;As a result, Talky is incredibly flexible and secure. We can add features, make specific implementations for our clients, integrate with “competing” services, and benefit from the maturity of the specifications and code around it.&lt;/p&gt;
&lt;p&gt;All of the components, save for some UI logic, of Talky are open source as the &lt;a href=&quot;https://github.com/otalk/&quot;&gt;Otalk Platform&lt;/a&gt;. We’re particularly proud of &lt;a href=&quot;https://twitter.com/lancestout&quot;&gt;Lance&apos;s&lt;/a&gt; work on &lt;a href=&quot;http://stanza.io&quot;&gt;Stanza.io&lt;/a&gt; which makes working with XMPP in the browser painless and free of those pointy angle brackets. &lt;/p&gt;
&lt;p&gt;If you’d like our help using OTalk in your projects, you should &lt;a href=&quot;https://andyet.com/contact&quot;&gt;give us a call&lt;/a&gt; or even ask us to join a Talky room.&lt;/p&gt;
&lt;p&gt;You can also show your support by spreading the word about our &lt;a href=&quot;https://www.kickstarter.com/projects/talky/talky-the-first-truly-simple-video-chat&quot;&gt;Kickstarter for Talky&lt;/a&gt;. We’d sure appreciate your support in our efforts to reclaim open standards for communication.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Talky Kickstarter is now live!]]></title><description><![CDATA[Talky Kickstarter is liveOur Kickstarter has officially launched!You can contribute to Talky — The First Truly Simple Video Chat project now…]]></description><link>https://blog.andyet.com/2015/05/27/kickstarter-goes-live/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/27/kickstarter-goes-live/</guid><pubDate>Wed, 27 May 2015 10:45:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/talky-kickstarter-lauch-header-02.png&quot; alt=&quot;Talky Kickstarter is live&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our Kickstarter has officially launched!&lt;/p&gt;
&lt;p&gt;You can contribute to &lt;a href=&quot;https://www.kickstarter.com/projects/talky/talky-the-first-truly-simple-video-chat&quot;&gt;Talky — The First Truly Simple Video Chat&lt;/a&gt; project now.&lt;/p&gt;
&lt;p&gt;Please help us spread the word! &lt;/p&gt;
&lt;p&gt;If you agree with the following then pass our Kickstarter link along.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Video chat should be easy&lt;/li&gt;
&lt;li&gt;The web needs more open platforms &lt;/li&gt;
&lt;li&gt;We need more people building cool things with WebRTC&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&apos;s to an exciting endeavor!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Tomorrow we Kickstart(er) Talky]]></title><description><![CDATA[Talky Kickstarter begins in 24 hours  For those of you with eagle eyes, yes we said we were going to launch it earlier this month, but when…]]></description><link>https://blog.andyet.com/2015/05/26/24-hours-to-kickstarter/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/26/24-hours-to-kickstarter/</guid><pubDate>Tue, 26 May 2015 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/talky-Kickstarter-header-24hrs-01.png&quot; alt=&quot;Talky Kickstarter begins in 24 hours&quot;&gt;  &lt;/p&gt;
&lt;p&gt;For those of you with eagle eyes, yes we said we were going to launch it earlier this month, but when it came time we discovered we needed to tweak things just a little bit more.&lt;/p&gt;
&lt;p&gt;Now we&apos;re ready. &lt;/p&gt;
&lt;p&gt;I’m excited to share with you that at 10am (PDT) tomorrow, May 27, the Kickstarter for Talky will go live and so will the opportunity to help push forward both the open web and WebRTC.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why are we doing this?&lt;/strong&gt; Well first, we believe in the importance of quality communication but you can read about the rest of the reasons &lt;a href=&quot;https://blog.andyet.com/2015/04/30/announcing-kickstarter&quot;&gt;we’ve written at length on here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What types of rewards are you offering?&lt;/strong&gt; Expect to see some brilliant swag designs from the very talented &lt;a href=&quot;https://andyet.com/team/amy&quot;&gt;Amy Lynn Taylor&lt;/a&gt;, as well as dangerously discounted product (think Talky white label, etc.) and opportunites to get to collaborate with the whole &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt; team, led by &lt;a href=&quot;https://andyet.com/team/fippo&quot;&gt;WebRTC expert Philipp “Fippo” Hancke&lt;/a&gt;, on your projects.&lt;/p&gt;
&lt;p&gt;Mark your calendars! May 27 at 10am PDT Talky’s Kickstarter goes live! &lt;/p&gt;</content:encoded></item><item><title><![CDATA[RealtimeConf Call for Speakers is now open]]></title><description><![CDATA[Three weeks ago we announced the return of RealtimeConf and we couldn’t be more excited.  While the conference still remains a curated…]]></description><link>https://blog.andyet.com/2015/05/21/realtimeconf-call-for-speakers-is-now-open/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/21/realtimeconf-call-for-speakers-is-now-open/</guid><pubDate>Thu, 21 May 2015 18:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Three weeks ago we &lt;a href=&quot;https://blog.andyet.com/2015/05/01/realtimeconf-returns&quot;&gt;announced the return of RealtimeConf&lt;/a&gt; and we couldn’t be more excited.  While the conference still remains a curated experience (and you can see what we’re talking about in the 2013 &lt;a href=&quot;https://vimeo.com/89585477&quot;&gt;recap on Vimeo&lt;/a&gt;) we’re doing something different this year—opening a Call for Speakers. &lt;/p&gt;
&lt;p&gt;We’re looking for presentations on all the things related to realtime technologies and surrounding topics (not necessarily technical). Remember that this is an event meant to inspire and challenge the people pushing the web forward. Multiple submissions are more than welcome, and encouraged.&lt;/p&gt;
&lt;h2 id=&quot;need-help&quot;&gt;&lt;a href=&quot;#need-help&quot; aria-label=&quot;need help permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Need Help?&lt;/h2&gt;
&lt;p&gt;We’re committed to facilitating both audience and speaker diversity. If you’re a first time speaker, worry not—we’re happy to walk you through the proposal process and talk preparations as well. Check the &lt;a href=&quot;http://realtimeconf.com/call-for-speakers/&quot;&gt;submission guidelines&lt;/a&gt; or simply reach out through &lt;a href=&quot;mailto:realtimeconf@realtimeconf.com&quot;&gt;email&lt;/a&gt; or &lt;a href=&quot;https://twitter.com/realtimeconf&quot;&gt;Twitter&lt;/a&gt; to request assistance.&lt;/p&gt;
&lt;p&gt;Additionally, we will be offering discounted tickets to all members of underrepresented groups who’s talks won’t be shortlisted.&lt;/p&gt;
&lt;h2 id=&quot;the-deadline&quot;&gt;&lt;a href=&quot;#the-deadline&quot; aria-label=&quot;the deadline permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Deadline&lt;/h2&gt;
&lt;p&gt;We are accepting talk proposals until &lt;strong&gt;June 22&lt;/strong&gt;. &lt;/p&gt;
&lt;h2 id=&quot;submit-a-talk&quot;&gt;&lt;a href=&quot;#submit-a-talk&quot; aria-label=&quot;submit a talk permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Submit a talk&lt;/h2&gt;
&lt;p&gt;You can apply through the &lt;a href=&quot;http://realtimeconf.com/call-for-speakers/&quot;&gt;RealtimeConf website&lt;/a&gt;—we can’t wait to see what you come up with!&lt;/p&gt;
&lt;h2 id=&quot;but-what-about-the-tickets&quot;&gt;&lt;a href=&quot;#but-what-about-the-tickets&quot; aria-label=&quot;but what about the tickets permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But what about the tickets?&lt;/h2&gt;
&lt;p&gt;We will be releasing first, very limited batch of Early Bird tickets at &lt;strong&gt;$1299&lt;/strong&gt; on &lt;strong&gt;June 2 at 10am PST&lt;/strong&gt; (and if you&apos;re not located in Pacific time zone you can easily compare time &lt;a href=&quot;http://time.is/compare/1000_2_June_2015_in_Richland,_Washington&quot;&gt;here&lt;/a&gt; to make sure not to miss it!). This includes three nights of accommodations, six meals, and a wall-to-wall experience starting when you arrive into town. &lt;/p&gt;
&lt;p&gt;Sign up to be notified on &lt;a href=&quot;http://realtimeconf.com&quot;&gt;RealtimeConf website&lt;/a&gt; or follow &lt;a href=&quot;https://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/realtimeconf&quot;&gt;@realtimeconf&lt;/a&gt; on Twitter.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Ode to legacy code]]></title><description><![CDATA[The other day I was trying to add some functionality to a project I was writing some code for. It was a project with many people on it, and…]]></description><link>https://blog.andyet.com/2015/05/21/ode-to-legacy-code/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/21/ode-to-legacy-code/</guid><pubDate>Thu, 21 May 2015 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;The other day I was trying to add some functionality to a project I was writing some code for. It was a project with many people on it, and it was well under way when I got there. I was told that some of what I was going to be writing had been figured out already by another teammate, so I went to see what I could learn from their work.&lt;/p&gt;
&lt;p&gt;Turns out, a lot.&lt;/p&gt;
&lt;p&gt;You see, it ended up taking me about a day to ship the feature. But that day of work was built off of the weeks of work that my coworker had spent shaking out all the quirks, holes in documentation, and edge cases already solved when they worked on their part of the project.&lt;/p&gt;
&lt;p&gt;They made my job look easy. It was tempting in hindsight to say, “Of course this is the way to do it,” after seeing their code. It wasn’t though. If they hadn’t laid the groundwork before me I’d have spent the same amount of time (or more) than they did just to get to where things were at when I started.&lt;/p&gt;
&lt;h3 id=&quot;solving-the-problem&quot;&gt;&lt;a href=&quot;#solving-the-problem&quot; aria-label=&quot;solving the problem permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Solving the problem&lt;/h3&gt;
&lt;p&gt;There is value in solving the problem. Even if it’s in a piece of code or a project that never quite sees the light of day, or if you’re tempted to look back on as primitive or naive, it’s not. It’s only naive in the hindsight of the work you put in to make it.&lt;/p&gt;
&lt;p&gt;Iterating on battle-hardened code is way easier. Don’t be discouraged if your code was first but can be improved. You can only focus on one or the other: solving the problem or iterating on a solution. This is why premature optimization is discouraged, the optimization can come later. Even if it’s by someone else, they are still optimizing your solved code.&lt;/p&gt;
&lt;h3 id=&quot;monads-and-semicolons&quot;&gt;&lt;a href=&quot;#monads-and-semicolons&quot; aria-label=&quot;monads and semicolons permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Monads and semicolons&lt;/h3&gt;
&lt;p&gt;This is one of the reasons I simply can’t follow along when people start arguing about technicalities before things are solved. All their arguments are predicated off of the code working in the first place, that part can’t be replaced. Being opinionated about code needs to take this into account.&lt;/p&gt;
&lt;h2 id=&quot;not-done-but-complete&quot;&gt;&lt;a href=&quot;#not-done-but-complete&quot; aria-label=&quot;not done but complete permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Not done, but complete&lt;/h2&gt;
&lt;p&gt;Software is never done, but it can be not complete. This is a subtle but important distinction. There is no ‘done’ break point, but there is one for ‘this works now.’  I invite you to give yourself the credit for the latter.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt; I’m a reactive programmer: I wait for bugs then react to them&lt;br&gt;
--Gar&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;get-out-there-and-write&quot;&gt;&lt;a href=&quot;#get-out-there-and-write&quot; aria-label=&quot;get out there and write permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Get out there and write&lt;/h3&gt;
&lt;p&gt;So get out there, write your code without fear. Even if it never quite takes off, and someone else comes along and shows you how it could be better. They can’t improve on something that never existed in the first place.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Navigator Office Hours: Node Security]]></title><description><![CDATA[Next week on May 28th I'm going to host the second Navigator Office Hours focused around Node Security.For the last 3+ years I’ve been…]]></description><link>https://blog.andyet.com/2015/05/20/navigator-office-hours-node-security/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/20/navigator-office-hours-node-security/</guid><pubDate>Wed, 20 May 2015 14:55:00 GMT</pubDate><content:encoded>&lt;p&gt;Next week on May 28th I&apos;m going to host the second &lt;a href=&quot;https://seaworthy.io/#services&quot;&gt;Navigator Office Hours&lt;/a&gt; focused around Node Security.&lt;/p&gt;
&lt;p&gt;For the last 3+ years I’ve been focused on helping developers build more secure Node.js applications. We found a lot of patterns and tools that work and have done significant amount of research into the Node ecosystem, which I’ll briefly talk about.&lt;/p&gt;
&lt;p&gt;I will also give a quick demo of &lt;a href=&quot;https://requiresafe.com&quot;&gt;requireSafe&lt;/a&gt; and maybe give a sneak peak of some features to be included in the upcoming release.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Most importantly, this will be a collaborative forum to get your questions get answered. I’m here to provide guidance and offer whatever help I can.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Please join me and &lt;a href=&quot;https://ti.to/seaworthy/navigator-office-hours-with-adam-baldwin&quot;&gt;register now&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Lazymorphic Apps: Bringing back the static web]]></title><description><![CDATA[We’ve come long way from the simple static sites of the early web, yet somehow, I really miss it.It was so awesomely simple to be able to…]]></description><link>https://blog.andyet.com/2015/05/18/lazymorphic-apps-bringing-back-static-web/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/18/lazymorphic-apps-bringing-back-static-web/</guid><pubDate>Mon, 18 May 2015 14:55:00 GMT</pubDate><content:encoded>&lt;p&gt;We’ve come long way from the simple static sites of the early web, yet somehow, I really miss it.&lt;/p&gt;
&lt;p&gt;It was so awesomely simple to be able to write some HTML, CSS, and JavaScript, then FTP those files to a server somewhere and “Bam!” a site is launched!&lt;/p&gt;
&lt;p&gt;Of course we can still do that for simple static content, but what about &lt;a href=&quot;https://blog.andyet.com/2015/01/22/native-web-apps&quot;&gt;native web apps&lt;/a&gt; (a.k.a. single page apps).&lt;/p&gt;
&lt;h2 id=&quot;can-we-build-apps-as-static-sites&quot;&gt;&lt;a href=&quot;#can-we-build-apps-as-static-sites&quot; aria-label=&quot;can we build apps as static sites permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Can we build apps as static sites?&lt;/h2&gt;
&lt;p&gt;Certainly. It’s hardly a new idea. Today’s browsers are incredibly capable runtimes. We can use HTML, CSS, JS, and the built-in browser APIs to do &lt;a href=&quot;http://beta.talky.io/&quot;&gt;all&lt;/a&gt; &lt;a href=&quot;http://kevvv.in/mix/&quot;&gt;kinds&lt;/a&gt; of &lt;a href=&quot;http://www.vill.ee/eye/&quot;&gt;awesome&lt;/a&gt; &lt;a href=&quot;https://aerotwist.com/blog/voice-memos/&quot;&gt;things&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But, many times as an app grows beyond the prototype stage, developers are quick to convert what is otherwise a completely static set of files into an app that also has a dynamic server-side process.&lt;/p&gt;
&lt;p&gt;Usually this is because of a few challenges that I’ll iterate through and discuss below.&lt;/p&gt;
&lt;p&gt;I’ve found that most of these reasons are easily addressed, and doing the work of keeping your app as a static set of files has some significant benefits.&lt;/p&gt;
&lt;h3 id=&quot;routing-and-clean-urls&quot;&gt;&lt;a href=&quot;#routing-and-clean-urls&quot; aria-label=&quot;routing and clean urls permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Routing and clean URLs&lt;/h3&gt;
&lt;p&gt;If we serve a native web app from a completely logic-less static file server this usually means ugly URLs in order to have them match specific files.&lt;/p&gt;
&lt;p&gt;So, instead of:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;example.com/about&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You may think we’d have to do:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;example.com/about.html&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, that’s fairly easy to address by having a bit of logic in a routing config that implies the &lt;code class=&quot;language-text&quot;&gt;.html&lt;/code&gt;. Many static file servers do this easily or even by default.&lt;/p&gt;
&lt;p&gt;But, perhaps more importantly, a completely logic-less file server will only answer requests that match specific HTML documents on our server. Without some kind of “catchall” there’s no way to truly do clientside routing in our native web apps.&lt;/p&gt;
&lt;p&gt;As a quick example you may want a URL like this in your app:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;example.com/products/widgets/42&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But unless your folder structure contains just such a file structure: &lt;code class=&quot;language-text&quot;&gt;www/products/widgets/42.html&lt;/code&gt; for example, you may not have a match. Also, you’ve now coupled your file structure to your URL scheme. Which may not be ideal.&lt;/p&gt;
&lt;p&gt;We can address that with a little bit of routing logic too.&lt;/p&gt;
&lt;p&gt;Imagine if our routing rules looked as follows:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Specific assets are just matched to structure&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;route:              file served:
site.com/pic.png -&amp;gt; pic.png&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;2. The &lt;code class=&quot;language-text&quot;&gt;.html&lt;/code&gt; is implied&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;route:           file served:
site.com/page -&amp;gt; page.html
site.com      -&amp;gt; index.html&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;3. Unmatched route, without file extensions, handled by catchall&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If a route that includes a file extension (such as &lt;code class=&quot;language-text&quot;&gt;.png&lt;/code&gt;) is requested, but missing, respond with a 404 code as usual.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;But&lt;/em&gt;, if something that looks like an application path (no file extension) is requested, always respond with whatever file you’ve specify as your catchall. Perhaps a &lt;code class=&quot;language-text&quot;&gt;200.html&lt;/code&gt; or a &lt;code class=&quot;language-text&quot;&gt;catchall.html&lt;/code&gt; from the root of your static file folder.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;route:                        file served:
site.com/missing-image.png -&amp;gt; 404
site.com/other-path        -&amp;gt; 200.html&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With just this bit of logic we can now serve a completely static set of files in a way that enables beautiful, clean URLs in our native web apps.&lt;/p&gt;
&lt;p&gt;The logic I’ve described above is exactly how &lt;a href=&quot;http://surge.sh&quot;&gt;Surge&lt;/a&gt; is configured out of the box. But it’s also not too difficult to create similar functionality in other routing systems. Using &lt;a href=&quot;http://nginx.org/en/docs/http/ngx_http_core_module.html#try_files&quot;&gt;nginx’s try_files&lt;/a&gt; directive, for example.&lt;/p&gt;
&lt;p&gt;I hope to see approaches like this become standard config options in file servers. It would be cool to see &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; add support for a 200.html file, for example.&lt;/p&gt;
&lt;h3 id=&quot;youll-most-certainly-need-a-build-step&quot;&gt;&lt;a href=&quot;#youll-most-certainly-need-a-build-step&quot; aria-label=&quot;youll most certainly need a build step permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;You’ll most certainly need a build step&lt;/h3&gt;
&lt;p&gt;I’d argue that in today’s web, if you’re writing any significant amount of JS it should probably go through a build step before being served to a browser anyway, at least for minification, if nothing else.&lt;/p&gt;
&lt;p&gt;But the need for a build step becomes even more apparent if you’re building an entire application as we’re describing here.&lt;/p&gt;
&lt;p&gt;You don’t want to have to write everything in just a couple of files, or have 40 different &lt;code class=&quot;language-text&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags in your HTML. It’s incredibly hard to stay organized that way.&lt;/p&gt;
&lt;p&gt;We’ve been using &lt;a href=&quot;http://npmjs.com/&quot;&gt;npm&lt;/a&gt; and CommonJS modules for frontend code at &lt;a href=&quot;http://andyet.com/&quot;&gt;&amp;#x26;yet&lt;/a&gt; for years. Since browsers don’t have a &lt;code class=&quot;language-text&quot;&gt;require&lt;/code&gt; function by default, CommonJS modules can’t be used in a browser without some kind of shim so we’ve become quite accustomed to build-steps anyway and at this point, we’re never going back.&lt;/p&gt;
&lt;p&gt;Also, with the emergence of ES6, we’ve also been adding a transpilation step to that build step to transpile ES6 into code that browsers can run (using &lt;a href=&quot;https://babeljs.io/&quot;&gt;babel.js&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;More on how I’ve been doing the builds below, but first...&lt;/p&gt;
&lt;h3 id=&quot;what-about-accessibility&quot;&gt;&lt;a href=&quot;#what-about-accessibility&quot; aria-label=&quot;what about accessibility permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about accessibility?&lt;/h3&gt;
&lt;p&gt;This seems to always come up despite the fact that rendering an app entirely in JS is no longer considered a problem for accessibility (read &lt;a href=&quot;http://www.paulirish.com/2012/accessibility-and-developers/&quot;&gt;this post by Paul Irish&lt;/a&gt;) as 98.6% of screenreaders in use (as of 2012) handle JS just fine.&lt;/p&gt;
&lt;p&gt;I’d encourage you to read that article for more detail. But making things keyboard accessible is far more important that avoiding JS.&lt;/p&gt;
&lt;h3 id=&quot;what-about-seo&quot;&gt;&lt;a href=&quot;#what-about-seo&quot; aria-label=&quot;what about seo permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about SEO?&lt;/h3&gt;
&lt;p&gt;This seems to be the most oft-mentioned concern with building applications that render content after the JS has executed. This is true. Pure JS-rendered sites can be plagued by this.&lt;/p&gt;
&lt;p&gt;A few points to consider:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Most of the cases where developers are wanting to build a native web app the use case requires a login anyway. For those cases, SEO is only relevant to the public pages, which I would suggest not rendering on the client anyway.&lt;/li&gt;
&lt;li&gt;This whole no-JS-for-SEO argument is losing steam as search engines are getting better at executing JS before indexing the content. &lt;a href=&quot;https://medium.com/ben-and-dion/is-it-time-to-go-spa-only-did-google-bot-put-a-nail-in-the-server-rendered-coffin-d3d4128d1ec0&quot;&gt;This article by Ben Galbraith and Dion Almaer&lt;/a&gt; suggests that JS-capable search is clearly the future and perhaps it’s time to skate where the puck is going to be.&lt;/li&gt;
&lt;li&gt;We can address this in full or in part by rendering all known HTML to static files ahead of time (more on this later in this post).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because the browser always gets “empty” HTML, it has to download, parse, and execute the entire JS payload before the user sees anything at all on their screen.&lt;/p&gt;
&lt;h3 id=&quot;what-about-the-applications-performance-hacker-news-told-me-to-build-isomorphic-applications&quot;&gt;&lt;a href=&quot;#what-about-the-applications-performance-hacker-news-told-me-to-build-isomorphic-applications&quot; aria-label=&quot;what about the applications performance hacker news told me to build isomorphic applications permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about the application’s performance? Hacker News told me to build Isomorphic applications.&lt;/h3&gt;
&lt;p&gt;Browsers have been optimizing HTML rendering performance for years, turns out. If a server responds with a full HTML document and some CSS, browsers can turn that into a viewable webpage extremely quickly. That is, unless you do something to block it from doing so.&lt;/p&gt;
&lt;p&gt;The trouble with native web apps in this regard is that many people who build them serve “empty” HTML files, with a single &lt;code class=&quot;language-text&quot;&gt;&amp;lt;script src=&amp;quot;app.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; that includes the whole app.&lt;/p&gt;
&lt;p&gt;I’d like to point out that &lt;em&gt;this isn’t always a problem&lt;/em&gt;. If we can manage to download and cache that large JavaScript file, or even &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ&quot;&gt;prefetch the app&lt;/a&gt; while the user is typing their login or something, or if the JS file isn’t excessively huge (like many of them seem to be) it’s not necessarily an issue. For example the &lt;em&gt;entire&lt;/em&gt; JS required for the &lt;a href=&quot;http://todomvc.com/examples/ampersand/&quot;&gt;Ampersand.js version of TodoMVC&lt;/a&gt; is 28kb when minified and gzipped (smaller than jQuery by itself).&lt;/p&gt;
&lt;h3 id=&quot;isomorphic-apps-are-neat-but-can-be-messy&quot;&gt;&lt;a href=&quot;#isomorphic-apps-are-neat-but-can-be-messy&quot; aria-label=&quot;isomorphic apps are neat but can be messy permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Isomorphic apps are neat, but can be messy&lt;/h3&gt;
&lt;p&gt;If you’re not familiar with isomorphic applications, the term “isomorphic” could arguably be better explained as “portable JS” meaning that the code is written in a way that enables it to run in something like &lt;a href=&quot;http://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; on the server and also work in a browser.&lt;/p&gt;
&lt;p&gt;You can imagine if you build your entire application in such a way that it didn‘t care where it ran, you could simply run it on the server first and instead of responding with “empty” HTML, respond with the HTML that your app would have generated in the browser for that particular URL anyway.&lt;/p&gt;
&lt;p&gt;As it turns out, however, those environments are often &lt;em&gt;not&lt;/em&gt; very similar. Browsers have things like &lt;code class=&quot;language-text&quot;&gt;window&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;document&lt;/code&gt;, and a whole lot of browser APIs that simply wouldn’t have any place in a serverside environment (no need for &lt;code class=&quot;language-text&quot;&gt;navigator.getUserMedia&lt;/code&gt; for example).&lt;/p&gt;
&lt;p&gt;We also have to figure out a way to run a somewhat isolated browser-like environment &lt;em&gt;for each user&lt;/em&gt; if we have any user-specific data we also want to include. Of course, all these things can be done. But it’s complex, resource intensive, and frankly doesn’t feel like a reasonable expectation to set as a “best practice” for every app, nor as something that should be considered required knowledge for anyone wanting to build a “socially acceptable” web app.&lt;/p&gt;
&lt;h3 id=&quot;what-if-we-just-rendered-everything-we-know-at-build-time&quot;&gt;&lt;a href=&quot;#what-if-we-just-rendered-everything-we-know-at-build-time&quot; aria-label=&quot;what if we just rendered everything we know at build time permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What if we just rendered everything we know at build time?&lt;/h3&gt;
&lt;p&gt;What if instead of trying to render &lt;em&gt;everything&lt;/em&gt;, what if we at least rendered everything we know at build time?&lt;/p&gt;
&lt;p&gt;Using the routing logic described above and something like React that lets us efficiently &lt;em&gt;morph&lt;/em&gt; the existing HTML (from our static HTML file) we could just pre-render &lt;em&gt;all known HTML structure at build time&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For funsies I’m referring to this technique as &lt;strong&gt;Lazymorphic rendering&lt;/strong&gt;. It’s not running a full isomorphic application in production, instead we simply pre-render as much of the application as we possibly can to static files at build-time.&lt;/p&gt;
&lt;h3 id=&quot;what-about-development-workflow&quot;&gt;&lt;a href=&quot;#what-about-development-workflow&quot; aria-label=&quot;what about development workflow permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about development workflow?&lt;/h3&gt;
&lt;p&gt;We don’t want to devolve to a mess of complex Grunt or Gulp configs either, but clearly, in order to build things in this way, we need a workflow that allows us to easily transition from development mode to bundling everything up for production.&lt;/p&gt;
&lt;p&gt;We really don’t want to introduce a slow build step that we have to run &lt;em&gt;each&lt;/em&gt; time we make a change. &lt;a href=&quot;http://webpack.github.io/&quot;&gt;Webpack&lt;/a&gt; and the &lt;a href=&quot;http://webpack.github.io/docs/webpack-dev-server.html&quot;&gt;webpack-dev-server&lt;/a&gt; are good tools to allow for this type of thing. Unfortunately, setting it all up in this way requires a lot of finagling with webpack configs.&lt;/p&gt;
&lt;p&gt;To make that easier I’ve open sourced a module called &lt;a href=&quot;https://github.com/henrikjoreteg/hjs-webpack&quot;&gt;hjs-webpack&lt;/a&gt; that basically just pre-configured webpack and a dev server. It makes setting up the workflow I’ve described a lot easier. There’s also a &lt;a href=&quot;http://learn.humanjavascript.com/react-ampersand/setting-up-webpack&quot;&gt;screencast&lt;/a&gt; that walks through setting it up and lets you see what it actually does.&lt;/p&gt;
&lt;h3 id=&quot;an-open-source-app-built-this-way&quot;&gt;&lt;a href=&quot;#an-open-source-app-built-this-way&quot; aria-label=&quot;an open source app built this way permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;An open source app built this way&lt;/h3&gt;
&lt;p&gt;There’s also an entire open source app at &lt;a href=&quot;http://hubtags.com/&quot;&gt;HubTags.com&lt;/a&gt; that has this workflow all set up. Instructions on how to run it yourself are &lt;a href=&quot;https://github.com/henrikjoreteg/hubtags.com#running-it&quot;&gt;in the readme file for the app&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Like many native web apps it has some public marketing pages and then all the “app” experience portions that exist behind the login prompt.&lt;/p&gt;
&lt;p&gt;In this simple example app we end up with two files at build time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;index.html&lt;/strong&gt;: the public marketing page&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;200.html&lt;/strong&gt;: the HTML that is shared among all the app pages. Things like layout, CSS, main navigation, etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If we followed the routing rules above, this means that &lt;code class=&quot;language-text&quot;&gt;site.com&lt;/code&gt; would serve the index file and &lt;code class=&quot;language-text&quot;&gt;200.html&lt;/code&gt; would be served at &lt;code class=&quot;language-text&quot;&gt;site.com/**anything here**&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;can-we-do-even-more-work-at-build-time&quot;&gt;&lt;a href=&quot;#can-we-do-even-more-work-at-build-time&quot; aria-label=&quot;can we do even more work at build time permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Can we do even more work at build time?!&lt;/h3&gt;
&lt;p&gt;Maybe. What &lt;em&gt;if&lt;/em&gt; we did this even for dynamic, but public data? Things like product pages in an e-commerce site could arguably be generated to pre-rendered to static files at build time too, right?&lt;/p&gt;
&lt;p&gt;I mean, why not, right?!&lt;/p&gt;
&lt;p&gt;Unless it’s user-specific or secured data, we could just generate pages for each of those products at build time too. If we do that we could even bootstrap the structured data we know that our JS is going to need by rendering the JSON into a &lt;code class=&quot;language-text&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag page while we’re generating the HTML.&lt;/p&gt;
&lt;h3 id=&quot;it-may-not-solve-everything-but-it-sure-works-well-for-most-things&quot;&gt;&lt;a href=&quot;#it-may-not-solve-everything-but-it-sure-works-well-for-most-things&quot; aria-label=&quot;it may not solve everything but it sure works well for most things permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It may not solve everything, but it sure works well for most things&lt;/h3&gt;
&lt;p&gt;I haven’t yet tried this on something with a lot of public pages, such as an online store, but it’s worked beautifully on things we have used it for.&lt;/p&gt;
&lt;p&gt;Just think about what we get:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pixels on the screen immediately&lt;/li&gt;
&lt;li&gt;Replace front-end servers with a CDN that serves static files, faster delivery, less likely to have downtime.&lt;/li&gt;
&lt;li&gt;Any known public content is available statically, even without JS.&lt;/li&gt;
&lt;li&gt;A nice development workflow&lt;/li&gt;
&lt;li&gt;Totally crawlable public pages&lt;/li&gt;
&lt;li&gt;JS takes over when downloaded and fills in any dynamic portions we don’t already have.&lt;/li&gt;
&lt;li&gt;If we use regular &lt;code class=&quot;language-text&quot;&gt;&amp;lt;a&amp;gt;&lt;/code&gt; tags for navigation, even internal navigation works without JS, but if we do have it, JS intercepts the clicks and navigates internally.&lt;/li&gt;
&lt;li&gt;Dramatically simplified ops and deployment. You could just deploy with something like &lt;a href=&quot;http://linux.die.net/man/1/rsync&quot;&gt;rsync&lt;/a&gt;. Or use a service like &lt;a href=&quot;http://surge.sh/&quot;&gt;Surge.sh&lt;/a&gt; or &lt;a href=&quot;http://divshot.com/&quot;&gt;Divshot&lt;/a&gt; to do it for you.&lt;/li&gt;
&lt;li&gt;No complex isomorphic application we have to run in production, yet we still get many of the benefits.&lt;/li&gt;
&lt;li&gt;By nature of the approach we’ve arguably built an app that’s offline-ready, in that it has very clearly cache-able assets and fetches all its data from external sources.&lt;/li&gt;
&lt;li&gt;We’re already prepared if we want to distribute the app in a wrapper like PhoneGap, Cordova, etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;what-about-authentication-and-sessions&quot;&gt;&lt;a href=&quot;#what-about-authentication-and-sessions&quot; aria-label=&quot;what about authentication and sessions permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about authentication and sessions?&lt;/h3&gt;
&lt;p&gt;If we don’t have a server that we’re running in production how do we handle logins and sessions?&lt;/p&gt;
&lt;p&gt;If you’ve built against a 3rd party API before you may have implemented a web application flow for something like OAuth. This can also be handled entirely without a server.&lt;/p&gt;
&lt;p&gt;Redirects are easy: &lt;code class=&quot;language-text&quot;&gt;window.location = &amp;#39;http://newsite.com&amp;#39;&lt;/code&gt; and we can make AJAX requests to fetch tokens, etc. Once we have an API token, we can use that to make authenticated requests to the API server.&lt;/p&gt;
&lt;p&gt;Authentication tokens can be safely stored in a browsers’s &lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt;. Doing it all this way isn’t necessarily any harder, it’s just different that using a server framework’s built-in session systems.&lt;/p&gt;
&lt;p&gt;This is demonstrated in the &lt;a href=&quot;http://hubtags.com&quot;&gt;open source HubTags app&lt;/a&gt; app I mentioned before.&lt;/p&gt;
&lt;p&gt;If you’ve done OAuth before or are security minded, you’re already predicting the next section:&lt;/p&gt;
&lt;h3 id=&quot;what-about-keeping-secrets&quot;&gt;&lt;a href=&quot;#what-about-keeping-secrets&quot; aria-label=&quot;what about keeping secrets permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about keeping secrets?&lt;/h3&gt;
&lt;p&gt;If we compile everything to static files we can’t store secrets in them, right? Not in plain text, no.&lt;/p&gt;
&lt;p&gt;But we can run micoservices that are responsible for keeping our secrets for things like OAuth Client Secrets. To demonstrate this, the &lt;a href=&quot;http://hubtags.com&quot;&gt;HubTags&lt;/a&gt; app does OAuth with GitHub using a &lt;a href=&quot;https://github.com/prose/gatekeeper&quot;&gt;little micro-server&lt;/a&gt; whose only purpose is to keep our Client Secret, well... secret. You can deploy your own one for free to Heroku literally &lt;a href=&quot;https://github.com/prose/gatekeeper#deploy-on-heroku&quot;&gt;by clicking this button&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another cool approach to this kind of thing is &lt;a href=&quot;http://webtask.io/&quot;&gt;webtask.io&lt;/a&gt;. It uses JSON web tokens to encrypt secrets in a way that makes it safe for them to part of the static code in your app. You write a Node.js script that exists at a URL and your secret data is encrypted into the tokens you generate.&lt;/p&gt;
&lt;h3 id=&quot;what-about-fetching-data&quot;&gt;&lt;a href=&quot;#what-about-fetching-data&quot; aria-label=&quot;what about fetching data permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about fetching data?&lt;/h3&gt;
&lt;p&gt;Of course, by building this way, all the dynamic data that we can’t know at build time has to come from an external API. &lt;strong&gt;I see this as a feature&lt;/strong&gt;. Building in this way helps you separate presentation concerns for data/API concerns. Your web app becomes a true standalone native web app that sits right alongside any other apps you’ve built for your service.&lt;/p&gt;
&lt;p&gt;Since all dynamic data is external, there will inevitably be some additional network requests required to fetch the dynamic data, but we can mitigate &lt;em&gt;a lot&lt;/em&gt; of this by caching things like user data locally and trusting caches first, just like we’d do in a native app.&lt;/p&gt;
&lt;p&gt;New technologies like &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/service-worker/introduction/&quot;&gt;ServiceWorker&lt;/a&gt; will grant us even more power in this regard.&lt;/p&gt;
&lt;p&gt;But, we can optimize a lot of this kind of stuff just by caching JSON responses in &lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt; and including/checking timestamps that we store along with that data. Some tools like &lt;a href=&quot;http://firebase.com/&quot;&gt;FireBase&lt;/a&gt; will even do this for you seamlessly for things like user authentication data.&lt;/p&gt;
&lt;h3 id=&quot;want-to-see-more&quot;&gt;&lt;a href=&quot;#want-to-see-more&quot; aria-label=&quot;want to see more permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Want to see more?&lt;/h3&gt;
&lt;p&gt;I recently recorded a whole &lt;a href=&quot;http://learn.humanjavascript.com/react-ampersand&quot;&gt;5 hour tutorial&lt;/a&gt; showing line-by-line how to build an app this way using &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt; and &lt;a href=&quot;http://reactjs.com/&quot;&gt;React&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Or if you want to talk in person sign up for a short office hours that I’m hosting on &lt;a href=&quot;https://ti.to/seaworthy/navigator-office-hours-with-henrik-joreteg&quot;&gt;Thursday morning at 9 PT this week&lt;/a&gt;. I’m going to do a short 30-minute online presentation covering some of this same material, then we’ll have a discussion about it. Would love to have you join me.&lt;/p&gt;
&lt;p&gt;You can also hit me up on Twitter at &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt;. Would love to hear your thoughts and feedback on this.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Talky & Otalk on VUC #541]]></title><description><![CDATA[&yet CTO Peter Saint-Andre will make a guest appearance tomorrow at 9 AM Pacific on episode 541 of the VoIP Users Conference, a weekly, live…]]></description><link>https://blog.andyet.com/2015/05/14/talky-otalk-vuc/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/14/talky-otalk-vuc/</guid><pubDate>Thu, 14 May 2015 14:49:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;#x26;yet CTO &lt;a href=&quot;https://andyet.com/team/peter&quot;&gt;Peter Saint-Andre&lt;/a&gt; will make a guest appearance tomorrow at 9 AM Pacific on episode 541 of the &lt;a href=&quot;http://www.voipusersconference.org&quot;&gt;VoIP Users Conference&lt;/a&gt;, a weekly, live discussion about VoIP, SIP, Asterisk, WebRTC, and all things telephony. &lt;/p&gt;
&lt;p&gt;Likely topics will include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our plans for &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt;, including the upcoming &lt;a href=&quot;https://blog.andyet.com/2015/04/30/announcing-kickstarter&quot;&gt;Kickstarter campaign&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Our experience with XMPP &amp;#x26; WebRTC, the Jitsi Videobridge, and other parts of the &lt;a href=&quot;https://otalk.org/&quot;&gt;Otalk&lt;/a&gt; platform&lt;/li&gt;
&lt;li&gt;How to improve the developer experience for WebRTC&lt;/li&gt;
&lt;li&gt;Where we are seeing the most activity in WebRTC applications &lt;/li&gt;
&lt;li&gt;Is the age of the general-purpose communications app over?&lt;/li&gt;
&lt;li&gt;Will we ever see federation with WebRTC - or just more silos? &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Visit the &lt;a href=&quot;http://www.voipusersconference.org&quot;&gt;VUC homepage&lt;/a&gt; on the Interwebs for all the details on how to join the conversation in realtime (video recording to follow).&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Failing gracefully at this month’s TechTok]]></title><description><![CDATA[This month, &yet’s lead WebRTC engineer Philipp “Fippo” Hancke has been invited to speak at Tokbox’s TechTok on May 21. As a veteran…]]></description><link>https://blog.andyet.com/2015/05/13/failing-gracefully-at-techtok/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/13/failing-gracefully-at-techtok/</guid><pubDate>Wed, 13 May 2015 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;This month, &amp;#x26;yet’s lead WebRTC engineer &lt;a href=&quot;https://andyet.com/team/fippo&quot;&gt;Philipp “Fippo” Hancke&lt;/a&gt; has been invited to speak at Tokbox’s &lt;a href=&quot;http://www.tokbox.com/blog/techtok-failing-gracefully-with-webrtc/&quot;&gt;TechTok on May 21&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;As a veteran software developer, messaging and distributed systems have been a passion of Fippo for many years. He is also one of the leading non-Google contributors to the webrtc.org WebRTC library, which is used by Chrome, Opera, Google’s iOS and Android WebRTC SDKs, and others.&lt;/p&gt;
&lt;p&gt;This TechTok will focus on &lt;a href=&quot;http://www.tokbox.com/blog/techtok-failing-gracefully-with-webrtc/&quot;&gt;Failing gracefully with WebRTC,&lt;/a&gt; or everything you need to know about how to handle failures with WebRTC.&lt;/p&gt;
&lt;p&gt;Register to attend TechTok &lt;a href=&quot;http://www.meetup.com/TechToks-at-TokBox/events/222220505/&quot;&gt;here&lt;/a&gt; however, if you can’t make it to this event, Tokbox will have a limited number of virtual seats available so tweet at them at &lt;a href=&quot;https://twitter.com/tokbox&quot;&gt;@tokbox&lt;/a&gt; if you’re interested. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Microservices User Info and Authorization]]></title><description><![CDATA[Microservice is a buzz-word we’ve been hearing a lot of lately, however, it’s neither a new concept, nor is it a bad idea. Writing your…]]></description><link>https://blog.andyet.com/2015/05/12/micro-services-user-info-and-auth/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/12/micro-services-user-info-and-auth/</guid><pubDate>Tue, 12 May 2015 15:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Microservice is a buzz-word we’ve been hearing a lot of lately, however, it’s neither a new concept, nor is it a bad idea. Writing your processes as APIs in such a way that they can be run many times enables horizontal scaling and availability and has been a common &lt;a href=&quot;https://blog.andyet.com/2015/01/15/find-your-own-best-practices-for-node-with-node-consulting&quot;&gt;best practice&lt;/a&gt; for quite awhile, but the subtleties of dealing with user information in a microservice should be addressed.&lt;/p&gt;
&lt;h2 id=&quot;authentication-and-authorization&quot;&gt;&lt;a href=&quot;#authentication-and-authorization&quot; aria-label=&quot;authentication and authorization permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Authentication and Authorization&lt;/h2&gt;
&lt;p&gt;Each microservice should not have to do its own authentication, but it does need to do its own authorization. At &lt;a href=&quot;https://seaworthy.io&quot;&gt;Seaworthy&lt;/a&gt;, we like to run an openid-connect (an oAuth extension) service that handles logins and token generation separate from the rest of the APIs, which lines up pretty well with the whole microservice way of doing things. In the end, the other APIs receive the &lt;a href=&quot;http://jwt.io/&quot;&gt;webtoken&lt;/a&gt; either directly or are pre-validated through a gateway. The API can safely assume each request is authenticated, but this doesn’t give us much in the way of object-level permissions (AKA authorization).&lt;/p&gt;
&lt;p&gt;Each API should keep track of its own object-level permissions, and it can do so without anything more than a pre-validated userid or groupid. Simply record an object or row that has the id of the object, the id of the user or group, and a set of flags for which permissions they have on that object. That way, when a user tries to do an action on an object, we can join to the appropriate permissions object if it exists, and determine what the user can and can&apos;t do to that object. The point is, object-level-permissions exists in the microservice database store without extra user context.&lt;/p&gt;
&lt;p&gt;A pseudo-code example of how you might check an object-level permission before updating in an SQL database:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; objecttype_access &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; userid&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;$userid &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; objectid&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;$objectid &lt;span class=&quot;token operator&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; objecttype &lt;span class=&quot;token keyword&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;$&lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;WHERE&lt;/span&gt; objectid&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;$objectid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only users who can change permissions or have any access to REST routes that involve permissions, should be users with a special administrator or group-administrator scope in their webtoken. This way, you can bootstrap and manage the permissions for other users.&lt;/p&gt;
&lt;p&gt;A Node.js &lt;a href=&quot;https://www.npmjs.com/package/hapi&quot;&gt;hapi&lt;/a&gt; example of how you might check for “api_admin” scope before you allow adding an object-level permission:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;server&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; method&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;post&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/someobject_access&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    auth&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; scope&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;api_admin&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; pl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;insert into objectttype_access (userid, objectid, read, write) values ($1, $2, $3, $4)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;objectid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;read&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; Boom&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;badImplementation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Adding permission failed.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using this approach we do not require extra user information for authorization such as the username and/or email address - that information is stored elsewhere and only required for authentication.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.andyet.com/images/micro-service-high-level.png&quot; alt=&quot;a microservice layout chart&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;user-info-for-the-client&quot;&gt;&lt;a href=&quot;#user-info-for-the-client&quot; aria-label=&quot;user info for the client permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;User Info For the Client&lt;/h2&gt;
&lt;p&gt;When a client is using your microservice, and an object refers to a user, the microservice’s API should only send back the userid it is referring to. If the client needs more information about that user, like the display name, it should query the user information microservice, and possibly cache the result. Your user information service should really only display public information about the user, unless it keeps track of object level permissions on things like email addresses. Keep billing information, addresses, and password tokens in separate databases so that if this service is compromised, critical customer information isn’t.&lt;/p&gt;
&lt;p&gt;A Node.js &lt;a href=&quot;https://www.npmjs.com/package/wreck&quot;&gt;wreck&lt;/a&gt; example of using the API and filling in user information from a separate API:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;wreck&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://someapi.yourproject.com/someobjects&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;authorization&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; token&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  async&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;item&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mapcb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    wreck&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://user-info-api.yourproject.com/users/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;userid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; userResponse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mapcb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      item&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;user &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; userResponse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token function&quot;&gt;mapcb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; item&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; results&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; err&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In the end, remember to keep user information separate: authentication, billing, and identity information should all be in separate services with separate databases. Keep track of object-level permissions in the API that those objects live in, and manage permissions with special scopes. API clients should only get the immutable userid from your microservice API, and should cross-reference an identity API to get more context.&lt;/p&gt;
&lt;p&gt;If you follow these rules, you’ll have a way of building microservice APIs that are easy to write, don’t duplicate information, scale well, and keep your critical user-information separate.&lt;/p&gt;
&lt;p&gt;If you have a microservices problem... if no one else can help... and if you can find them... maybe you can hire... The &lt;a href=&quot;https://seaworthy.io&quot;&gt;Seaworthy&lt;/a&gt;-Team.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Navigator Office Hours set sail next week]]></title><description><![CDATA[When we set out creating services under the Seaworthy banner (our Node, Frontend and Ops Consulting services), we quickly realized that the…]]></description><link>https://blog.andyet.com/2015/05/12/navigator-office-hours/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/12/navigator-office-hours/</guid><pubDate>Tue, 12 May 2015 10:36:00 GMT</pubDate><content:encoded>&lt;p&gt;When we set out creating services under the &lt;a href=&quot;https://seaworthy.io/&quot;&gt;Seaworthy&lt;/a&gt; banner (our Node, Frontend and Ops Consulting services), we quickly realized that the best way to help you out was to be able to answer your questions (or at least be able to find you an answer). &lt;/p&gt;
&lt;p&gt;Quickly we realized that we needed to better understand a number of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What are the problems you’re currently facing?&lt;/li&gt;
&lt;li&gt;What does your workflow look like?&lt;/li&gt;
&lt;li&gt;Do you maintain a set of best practices?&lt;/li&gt;
&lt;li&gt;What are some of the paths you’ve already tried?&lt;/li&gt;
&lt;li&gt;Did you try turning if off and turning it on again? (Just kidding about that last one.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, in order to start those conversations, we created &lt;a href=&quot;https://seaworthy.io/#services&quot;&gt;Navigator Office Hours&lt;/a&gt;, a weekly hour-long session hosted by one of the many experienced Node developers on our team. &lt;/p&gt;
&lt;p&gt;For a $50 fee, you get face to face time with one of our Seaworthy Node veterans. Expect a short talk on the subject at hand, followed by an in-depth Q&amp;#x26;A, aka your chance to get expert help. &lt;/p&gt;
&lt;p&gt;The first one will be led by &lt;a href=&quot;http://humanjavascript.com/&quot;&gt;Human JavaScript&lt;/a&gt; author and &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand&lt;/a&gt; developer &lt;a href=&quot;https://andyet.com/team/henrik&quot;&gt;Henrik Joreteg&lt;/a&gt;. Henrik will talk about fundamentals of native web apps with Ampersand and React, as well as answer any questions for those looking to simplify the frontend. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ti.to/seaworthy/navigator-office-hours-with-henrik-joreteg&quot;&gt;Register for the first Navigator Office Hours with Henrik here.&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;The following week Navigator Office Hours will be led by &amp;#x26;yet’s Chief Security Officer, &lt;a href=&quot;https://liftsecurity.io&quot;&gt;^lift security&lt;/a&gt; team lead, and old-school Node security veteran &lt;a href=&quot;https://andyet.com/team/baldwin&quot;&gt;Adam Baldwin&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;For more on Navigator Office Hours or other Seaworthy services reach out at &lt;a href=&quot;mailto:contact@seaworthy.io&quot;&gt;contact@seaworthy.io&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Philipp Hancke to speak on his blackbox discoveries at Twilio’s Signal Conference]]></title><description><![CDATA[Lead &yet WebRTC engineer Philipp “fippo” Hancke has been very busy recently examining the inner workings of some of your favorite voice and…]]></description><link>https://blog.andyet.com/2015/05/11/fippo-at-signal/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/11/fippo-at-signal/</guid><pubDate>Mon, 11 May 2015 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Lead &amp;#x26;yet WebRTC engineer &lt;a href=&quot;https://andyet.com/team/fippo&quot;&gt;Philipp “fippo” Hancke&lt;/a&gt; has been very busy recently examining the inner workings of some of your favorite voice and video services. Just a few weeks ago, he wrote up his findings on the popular chat app WhatsApp for &lt;a href=&quot;https://webrtchacks.com/whats-up-with-whatsapp-and-webrtc/&quot;&gt;webrtcH4cKS&lt;/a&gt;. And this week, we have an analysis of &lt;a href=&quot;https://webrtchacks.com/facebook-webrtc/&quot;&gt;Facebooks Messenger service&lt;/a&gt;, which recently added videochat.&lt;/p&gt;
&lt;p&gt;You can also follow the series of reports at &lt;a href=&quot;https://andyet.com/webrtc-reports&quot;&gt;andyet.com/webrtc-reports&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Later this month, he’ll be speaking candidly about more of his discoveries at Twilio’s &lt;a href=&quot;http://signal.twilio.com/&quot;&gt;SIGNAL Conference&lt;/a&gt; in San Francisco. In &lt;a href=&quot;http://signal.twilio.com/speakers#philipp-hancke&quot;&gt;“WebRTC exposed: What we can learn from blackbox exploration of popular voice &amp;#x26; video services”&lt;/a&gt; fippo explains the findings as well as the lessons that can be learned for WebRTC.&lt;/p&gt;
&lt;p&gt;If you’ll be at SIGNAL be sure to ping &lt;a href=&quot;https://twitter.com/HCornflower&quot;&gt;fippo&lt;/a&gt;) or &lt;a href=&quot;https://twitter.com/stpeter&quot;&gt;Peter&lt;/a&gt; to say hello! &lt;/p&gt;
&lt;p&gt;For more on fippo&apos;s talk, or to register for the conference, visit &lt;a href=&quot;http://signal.twilio.com/&quot;&gt;signal.twilio.com&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Henrik continues campaign to rename Single Page Apps at SeattleJS]]></title><description><![CDATA[This Thursday Ampersand.js and Human JavaScript author Henrik Joreteg is speaking at SeattleJS in—you guessed it—Seattle!Fresh from his…]]></description><link>https://blog.andyet.com/2015/05/11/henrik-at-seattlejs/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/11/henrik-at-seattlejs/</guid><pubDate>Mon, 11 May 2015 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;This Thursday &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt; and &lt;a href=&quot;http://humanjavascript.com/&quot;&gt;Human JavaScript&lt;/a&gt; author &lt;a href=&quot;https://andyet.com/team/henrik&quot;&gt;Henrik Joreteg&lt;/a&gt; is speaking at &lt;a href=&quot;http://www.meetup.com/seattlejs/events/219694778/&quot;&gt;SeattleJS&lt;/a&gt; in—you guessed it—Seattle!&lt;/p&gt;
&lt;p&gt;Fresh from his appearance at this year’s Fluent Conf, Henrik will be speaking to the crew at SeattleJS on his opinions about &lt;a href=&quot;https://blog.andyet.com/2015/01/22/native-web-apps&quot;&gt;Native Web Apps&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Check out this &lt;a href=&quot;https://www.youtube.com/watch?v=bNwShmaITWE&quot;&gt;quick interview from Fluent&lt;/a&gt; on Native Web Apps (or is it Single Page Apps??).&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/bNwShmaITWE&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;  
&lt;br/&gt;  
    
Head over to [SeattleJS for Henrik’s overview on Ampersand, playing nicely with React](http://www.meetup.com/seattlejs/events/219694778/), and yes, probably that whole renaming Single Page Apps kerfuffle. 
&lt;p&gt;To register for Thursday’s event or sign up for other events visit the &lt;a href=&quot;http://www.meetup.com/seattlejs/events/219694778/&quot;&gt;SeattleJS meetup page&lt;/a&gt; and get acquainted!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Being true to our priorities, a shift in leadership at &yet]]></title><description><![CDATA[As founder, I (Adam Brault) have served as CEO of &yet since day one, and today we're making a change.Our website says, "&yet is about…]]></description><link>https://blog.andyet.com/2015/05/08/change/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/08/change/</guid><pubDate>Fri, 08 May 2015 13:36:00 GMT</pubDate><content:encoded>&lt;p&gt;As founder, I (&lt;a href=&quot;http://andyet.com/team/adam&quot;&gt;Adam Brault&lt;/a&gt;) have served as CEO of &amp;#x26;yet since day one, and today we&apos;re making a change.&lt;/p&gt;
&lt;p&gt;Our website &lt;a href=&quot;http://andyet.com/about&quot;&gt;says&lt;/a&gt;, &quot;&amp;#x26;yet is about people.&quot;&lt;/p&gt;
&lt;p&gt;I believe &lt;strong&gt;priorities are what you &lt;em&gt;do&lt;/em&gt;, not what you say they are.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We say that &amp;#x26;yet is about people not as a cute feel-good line, but because we think it&apos;s the right thing to do, it&apos;s effective, and it works.&lt;/p&gt;
&lt;p&gt;When people feel great about themselves, when they are encouraged and supported, when their place on the team is clear, when they are matched with work that is the right amount of challenge, and when they have the ability to influence the organization they are part of, they are able to do truly great work as a team and grow while doing it. I am extremely passionate about this area and I&apos;m often discouraged that I don&apos;t get to spend as much time as I want to on it.&lt;/p&gt;
&lt;p&gt;I really want to spend more time supporting, encouraging, guiding, clarifying, coaching and creating.&lt;/p&gt;
&lt;p&gt;I want to rearrange my priorities according to my values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Therefore I am today stepping down as CEO of &amp;#x26;yet. I will be focusing on People.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In most companies this role is called &quot;HR&quot;, but we just say &quot;people&quot;. As it&apos;s well-put by my favorite organizational philosopher:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;People are not &quot;things&quot; to be manipulated, labeled, boxed, bought, and sold. Above all else, they are not &quot;human resources.&quot; They are entire human beings, containing the whole of the evolving universe, limitless until we start limiting them.&quot; (Dee Hock)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I will &lt;em&gt;also&lt;/em&gt; serve as &quot;Entrepreneur at Large&quot; in the company, working as a collaborator and supporter of people in their projects and efforts.&lt;/p&gt;
&lt;p&gt;But this isn&apos;t just about me and my role.&lt;/p&gt;
&lt;p&gt;People need individual support and encouragement—but they &lt;em&gt;also&lt;/em&gt; need sustained big-picture clarity, planning, and direction.&lt;/p&gt;
&lt;p&gt;That doesn&apos;t match well with my skills.&lt;/p&gt;
&lt;p&gt;I&apos;m good at creating clarity, but not good at maintaining it. I&apos;m good at coming up with ideas but not at planning. I&apos;m good at suggesting direction, but not good at deciding on it.&lt;/p&gt;
&lt;p&gt;5 years ago, I met &lt;a href=&quot;http://twitter.com/ericzanol&quot;&gt;Eric Zanol&lt;/a&gt;. On Twitter I saw what he talked about, what he read, and what he focused on. I knew he was a frontend dev, but what surprised me is the only thing he really seemed to post on Twitter at that time were articles and thoughts about how organizations should work. We got to know each other and became casual friends.&lt;/p&gt;
&lt;p&gt;Henrik and I took him out to lunch around 4 years ago and said we wanted him to become our COO. He said he had no experience doing this—and that was true.&lt;/p&gt;
&lt;p&gt;Over the past 4 years, he&apos;s learned what he needed to in order to operate &amp;#x26;yet as a company. He put in several years&apos; worth of hours doing client work (including some of the most tedious we&apos;ve ever done). He&apos;s busted his tail setting up for conferences. When people need help, he&apos;s one of the first to offer it. He&apos;s worked to resolve conflicts and coach people in doing their work. He&apos;s spent long days and late nights understanding how &amp;#x26;yet works and thinking about how it should—not at anyone&apos;s request, but because it&apos;s what he cares about. And he&apos;s literally read books. &lt;em&gt;Books!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For the past year and a half, Eric has had responsibility of our day-to-day operations as COO.&lt;/p&gt;
&lt;p&gt;Beginning today, he&apos;ll be serving as our CEO.&lt;/p&gt;
&lt;p&gt;And I couldn&apos;t be more excited about that.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The future of Talky]]></title><description><![CDATA[Talky Kickstarter bannerWe want to make Talky into a fully open and people-friendly alternative for realtime communication on the web and on…]]></description><link>https://blog.andyet.com/2015/05/06/future-of-talky/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/06/future-of-talky/</guid><pubDate>Wed, 06 May 2015 15:36:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/talky-kickstarter02.png&quot; alt=&quot;Talky Kickstarter banner&quot;&gt;&lt;/p&gt;
&lt;p&gt;We want to make &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt; into a fully open and people-friendly alternative for realtime communication on the web and on mobile devices.&lt;/p&gt;
&lt;p&gt;But we don’t just want Talky to be an open alternative to existing video chat options. &lt;strong&gt;We want it to be the absolute best solution.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We’ve already added some of the key features you’ve requested to the &lt;a href=&quot;https://beta.talky.io/&quot;&gt;beta version&lt;/a&gt; of Talky:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Meet with more than 15 people at a time&lt;/li&gt;
&lt;li&gt;Text chat so you can share links and other information&lt;/li&gt;
&lt;li&gt;Select exactly who you want to see on video&lt;/li&gt;
&lt;li&gt;An even better user experience&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’re also working on some great new features, but they’re not quite ready yet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The ability to share files in real time&lt;/li&gt;
&lt;li&gt;Reserved rooms so you can have your very own place to hang out&lt;/li&gt;
&lt;li&gt;Contact lists that will enable you to see when your friends and colleagues are online&lt;/li&gt;
&lt;li&gt;Better handoffs between WiFi and mobile, for when you’re on the move&lt;/li&gt;
&lt;li&gt;An updated version of our Talky iOS app&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And there are some bigger efforts we’d love to take on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recording for things like company meetings and video blogging&lt;/li&gt;
&lt;li&gt;Broadcasting so you can involve hundreds of people at a time&lt;/li&gt;
&lt;li&gt;Apps for Android, Windows, Mac, and Linux&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’re really excited about adding all these great features to Talky. With your help we’ll be able to do so faster than we could on our own. &lt;/p&gt;
&lt;p&gt;In a later post we’ll explain a bit more about why we think &lt;a href=&quot;https://www.kickstarter.com/hello?ref=footer&quot;&gt;Kickstarter&lt;/a&gt; is the perfect fundraising platform for a service like Talky. For more info about the upcoming campaign be sure to subscribe below. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[RealtimeConf returns]]></title><description><![CDATA[It gives us really deep joy to be able to officially announce that RealtimeConf will return in full force for 2015.No, we aren’t telling you…]]></description><link>https://blog.andyet.com/2015/05/01/realtimeconf-returns/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/01/realtimeconf-returns/</guid><pubDate>Fri, 01 May 2015 13:36:00 GMT</pubDate><content:encoded>&lt;p&gt;It gives us really deep joy to be able to officially announce that RealtimeConf will return in full force for 2015.&lt;/p&gt;
&lt;p&gt;No, we aren’t telling you anything about it.&lt;/p&gt;
&lt;p&gt;Yet.&lt;/p&gt;
&lt;p&gt;Okay, we’ll tell you some stuff.&lt;/p&gt;
&lt;h2 id=&quot;the-people&quot;&gt;&lt;a href=&quot;#the-people&quot; aria-label=&quot;the people permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The people&lt;/h2&gt;
&lt;p&gt;Most importantly, we’re thrilled to be back. RealtimeConf has always attracted an amazing lineup—of &lt;em&gt;attendees&lt;/em&gt;. We love the community we’ve built with this event and we miss you all tremendously!&lt;/p&gt;
&lt;h2 id=&quot;the-vision&quot;&gt;&lt;a href=&quot;#the-vision&quot; aria-label=&quot;the vision permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The vision&lt;/h2&gt;
&lt;p&gt;We’ll of course be true to the original vision of RealtimeConf—bringing a diverse set of technologists together to focus on the problems of realtime and what these emerging technologies mean for the future of the web. Expect great people, discussions, and talks around peer-to-peer, WebRTC, messaging, protocols, distributed systems, architecture, security, as well as the human side of all of the above.&lt;/p&gt;
&lt;h2 id=&quot;the-experience&quot;&gt;&lt;a href=&quot;#the-experience&quot; aria-label=&quot;the experience permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The experience&lt;/h2&gt;
&lt;p&gt;You can expect it to be special. (If you’re unfamiliar, see a recap of 2013’s event at &lt;a href=&quot;http://experience.realtimeconf.com&quot;&gt;experience.realtimeconf.com&lt;/a&gt;) We’ll feature materials designed by &lt;a href=&quot;http://twitter.com/amydearest&quot;&gt;Amy Lynn Taylor&lt;/a&gt;, original music by &lt;a href=&quot;http://twitter.com/obensource&quot;&gt;Ben Michel&lt;/a&gt;, and we’ll be returning to the world of [Something Greater than Artifice] by &lt;a href=&quot;http://twitter.com/mike_speegle&quot;&gt;Mike Speegle&lt;/a&gt;. Of course you can expect a lot of effort by the &amp;#x26;yet team, this year led by &lt;a href=&quot;http://twitter.com/jennatormanen&quot;&gt;Jenna Tormanen&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-dates&quot;&gt;&lt;a href=&quot;#the-dates&quot; aria-label=&quot;the dates permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The dates&lt;/h2&gt;
&lt;p&gt;The event will be three days—October 6, 7, and 8.&lt;/p&gt;
&lt;h2 id=&quot;the-location&quot;&gt;&lt;a href=&quot;#the-location&quot; aria-label=&quot;the location permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The location&lt;/h2&gt;
&lt;p&gt;RealtimeConf will be in &amp;#x26;yet’s hometown of &lt;strong&gt;Richland, Washington&lt;/strong&gt;. We’re a beautiful 3 hour drive from Portland or Seattle, with direct flights daily to our airport (&lt;a href=&quot;http://airportcod.es/#airport/psc&quot;&gt;PSC&lt;/a&gt;) from &lt;a href=&quot;http://airportcod.es/#airport/sfo&quot;&gt;SFO&lt;/a&gt;, &lt;a href=&quot;http://airportcod.es/#airport/pdx&quot;&gt;PDX&lt;/a&gt;, &lt;a href=&quot;http://airportcod.es/#airport/sea&quot;&gt;SEA&lt;/a&gt;, &lt;a href=&quot;http://airportcod.es/#airport/den&quot;&gt;DEN&lt;/a&gt;, &lt;a href=&quot;http://airportcod.es/#airport/msp&quot;&gt;MSP&lt;/a&gt;, and &lt;a href=&quot;http://airportcod.es/#airport/slc&quot;&gt;SLC&lt;/a&gt;. Also—&amp;#x26;yet owns a sweet school bus (of course), so we &lt;em&gt;might&lt;/em&gt; be able to come pick you up. :) Stay tuned on that!&lt;/p&gt;
&lt;h2 id=&quot;only-150-tickets&quot;&gt;&lt;a href=&quot;#only-150-tickets&quot; aria-label=&quot;only 150 tickets permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Only 150 tickets!&lt;/h2&gt;
&lt;p&gt;We will have &lt;em&gt;fewer&lt;/em&gt; spots available than 2013’s event. Early bird tickets will go on sale at $1299, which will include three nights of accommodations, six meals, and a wall-to-wall experience starting when you arrive into town. Register your interest at &lt;a href=&quot;http://realtimeconf.com/&quot;&gt;RealtimeConf.com&lt;/a&gt; to be the first receiving a notification.&lt;/p&gt;
&lt;h2 id=&quot;sponsorship&quot;&gt;&lt;a href=&quot;#sponsorship&quot; aria-label=&quot;sponsorship permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sponsorship&lt;/h2&gt;
&lt;p&gt;If you’re interested in sponsoring RealtimeConf, we’d love to talk to you. Ping us at &lt;a href=&quot;mailto:realtimeconf@realtimeconf.com&quot;&gt;realtimeconf@realtimeconf.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;call-for-speakers&quot;&gt;&lt;a href=&quot;#call-for-speakers&quot; aria-label=&quot;call for speakers permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Call for speakers&lt;/h2&gt;
&lt;p&gt;Coming soon. But this is key: &lt;strong&gt;imagination and ambition in talk proposals will be expected.&lt;/strong&gt; (If you’re from an underrepresented group, we’d love to help you put together a highly creative and engaging presentation.)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing Vorlon.JS]]></title><description><![CDATA[Vorlon.JSYesterday Microsoft announced Vorlon.JS, an open source tool for remotely debugging and testing your JavaScript. The team behind it…]]></description><link>https://blog.andyet.com/2015/05/01/introducing-vorlonjs/</link><guid isPermaLink="false">https://blog.andyet.com/2015/05/01/introducing-vorlonjs/</guid><pubDate>Fri, 01 May 2015 12:39:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/vorlon-js.png&quot; alt=&quot;Vorlon.JS&quot;&gt;&lt;/p&gt;
&lt;p&gt;Yesterday Microsoft announced &lt;a href=&quot;http://vorlonjs.com/&quot;&gt;Vorlon.JS&lt;/a&gt;, an open source tool for remotely debugging and testing your JavaScript. The team behind it wants to make debugging easier, quicker, and more consistent for developers across multiple platforms.&lt;/p&gt;
&lt;p&gt;That’s a goal we very much support and we’re excited we could play a role in getting Vorlon.JS ready for this release.&lt;/p&gt;
&lt;p&gt;We’ve built and contributed to a handful of &lt;a href=&quot;https://andyet.com/opensource&quot;&gt;open source&lt;/a&gt; projects ourselves, so Microsoft asked us to help them in open sourcing Vorlon.JS. As open source veterans, &lt;a href=&quot;https://andyet.com/team/henrik&quot;&gt;Henrik&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/phil&quot;&gt;Philip&lt;/a&gt;, and &lt;a href=&quot;https://andyet.com/team/bear&quot;&gt;Bear&lt;/a&gt; helped improve the developer experience of using the software and setting it up for community contributions.&lt;/p&gt;
&lt;p&gt;Our design and dev teams improved the UI and UX for the Vorlon.JS dashboard and &lt;a href=&quot;https://andyet.com/team/amy&quot;&gt;Amy&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/jaime&quot;&gt;Jaime&lt;/a&gt;, and &lt;a href=&quot;https://andyet.com/team/terry&quot;&gt;Terry&lt;/a&gt; led the design of the project’s identity and documentation that can be found at &lt;a href=&quot;http://vorlonjs.com/&quot;&gt;vorlonjs.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Vorlon.JS team shares our enthusiasm for clarity and simplicity (with some fun mixed in, of course) and we’re thrilled to see where they and the developer community take it.&lt;/p&gt;
&lt;p&gt;Check out the project on &lt;a href=&quot;https://github.com/MicrosoftDX/Vorlonjs/&quot;&gt;GitHub&lt;/a&gt; and the documentation at &lt;a href=&quot;http://vorlonjs.com/&quot;&gt;vorlonjs.com&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Coming soon: a Talky Kickstarter!]]></title><description><![CDATA[A Talky Kickstarter!Talky started as an interesting demo two years ago this February, but it became a product that has seen thousands and…]]></description><link>https://blog.andyet.com/2015/04/30/announcing-kickstarter/</link><guid isPermaLink="false">https://blog.andyet.com/2015/04/30/announcing-kickstarter/</guid><pubDate>Thu, 30 Apr 2015 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/Kickstarter_Countdown01.svg&quot; alt=&quot;A Talky Kickstarter!&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; started as an &lt;a href=&quot;http://blog.andyet.com/2013/02/22/introducing-simplewebrtcjs-and-conversatio&quot;&gt;interesting demo two years ago this February&lt;/a&gt;, but it became a product that has seen thousands and thousands of new users each month.&lt;/p&gt;
&lt;p&gt;We believe Talky can be an independent communication platform built entirely on open-source technologies (both our own code as well as great projects like &lt;a href=&quot;https://jitsi.org/&quot;&gt;Jitsi&lt;/a&gt;, &lt;a href=&quot;https://prosody.im/&quot;&gt;Prosody&lt;/a&gt;, and &lt;a href=&quot;http://creytiv.com/restund.html&quot;&gt;restund&lt;/a&gt;). We believe we can do it bootstrapped without VC funding or the support of a telco—and with security and your privacy in mind.&lt;/p&gt;
&lt;p&gt;In fact, it already is all of these things! &lt;/p&gt;
&lt;p&gt;But we need your help to make Talky stronger, better, faster and other things that would make Daft Punk finally proud of us. We don’t just want Talky to be an open alternative to existing solutions. We want it to be one of the &lt;em&gt;absolute best&lt;/em&gt; solutions. And with your help, it will be.&lt;/p&gt;
&lt;h1 id=&quot;why-not-just-charge-for-talky&quot;&gt;&lt;a href=&quot;#why-not-just-charge-for-talky&quot; aria-label=&quot;why not just charge for talky permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why not just charge for Talky?&lt;/h1&gt;
&lt;p&gt;In fact, we already &lt;em&gt;do&lt;/em&gt; have paid Talky customers for a version that you can run securely behind your company firewall (&lt;a href=&quot;https://andyet.com/talky&quot;&gt;contact us&lt;/a&gt; if you’re interested). :)&lt;/p&gt;
&lt;p&gt;Our intent is to always keep the basic Talky service free and available, in keeping with making it as easy as possible to use for anyone. We have a lot of plans for how we will make money from Talky, like: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use Talky’s core platform to build and run products for others who can’t or don’t want to integrate or maintain these kinds of technologies&lt;/li&gt;
&lt;li&gt;offer on-premises versions of Talky&lt;/li&gt;
&lt;li&gt;share our expertise with clients in technical consulting&lt;/li&gt;
&lt;li&gt;sell white label or branded versions of Talky&lt;/li&gt;
&lt;li&gt;give the option of paying for premium features&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We already do most of these in some capacity. (If you’re interested, &lt;a href=&quot;http://andyet.com/talky&quot;&gt;let’s talk!&lt;/a&gt;)&lt;/p&gt;
&lt;h1 id=&quot;so-why-do-we-need-your-support&quot;&gt;&lt;a href=&quot;#so-why-do-we-need-your-support&quot; aria-label=&quot;so why do we need your support permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So why do we need your support?&lt;/h1&gt;
&lt;p&gt;We’ve put two years into making Talky great and building open-source tools for web-based collaboration. But getting Talky to our ultimate goal of improved quality and accessibility will take more than we can give at the present. And we’re in it for the long-run with Talky, but it’s still in its early days.&lt;/p&gt;
&lt;p&gt;Our &lt;a href=&quot;https://andyet.com/team&quot;&gt;team of 30+ yetis&lt;/a&gt; balance the challenging dynamics of being a product company, as well as consultants and trainers, while maintaining a vibrant presence in the JS, WebRTC, and open-source communities.&lt;/p&gt;
&lt;p&gt;We’re asking you for the opportunity to focus on making what you already love even better.&lt;/p&gt;
&lt;p&gt;The future we see for Talky is an exciting one. We’ve been very hard at work on the technical fundamentals over the past two years, and we are thrilled to be able to turn even more of our focus to the real reason we&apos;re doing this: building an unparalleled user experience. &lt;/p&gt;
&lt;p&gt;As mentioned, we’ve already added the improved user experience, added text chat, and enabled larger conferences, but these features need further polishing and your feedback!&lt;/p&gt;
&lt;p&gt;In addition, there are some features we need your support on that are under development but need more work before they’re ready to release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;File sharing&lt;/li&gt;
&lt;li&gt;Reserved rooms&lt;/li&gt;
&lt;li&gt;Better handoffs between Wi-Fi and mobile networks&lt;/li&gt;
&lt;li&gt;Updated iOS app to support all of the above&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And finally there are some larger projects that we could take on as stretch goals if there’s enough interest:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Android app&lt;/li&gt;
&lt;li&gt;Opt-in recording&lt;/li&gt;
&lt;li&gt;Broadcast for even larger groups&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;why-kickstarter&quot;&gt;&lt;a href=&quot;#why-kickstarter&quot; aria-label=&quot;why kickstarter permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why Kickstarter?&lt;/h2&gt;
&lt;p&gt;Talky has been independently bootstrapped since Day One (no venture capitalists, no telco sponsors, no outside investors).  As a result, Kickstarter is the only form of fundraising that fits with our core philosophies as a team.&lt;/p&gt;
&lt;p&gt;We’re only willing to accept funding from the people we most want to deliver for: our awesome users. &lt;/p&gt;
&lt;p&gt;We want to provide an amazing service for a long time, not get acquired and sell our users to a bigger company. It only feels right for us to accept funding from the people who use Talky, love Talky, and want to see it improved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So this month, we’re kicking off a Kickstarter campaign to raise $60K to make Talky better.&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;By making Talky a stronger service and a viable alternative to, say, Skype or Google Hangouts, we’re empowering you with more options for how you choose to communicate. Bringing more attention and interest to the technology behind Talky, WebRTC, gets more folks involved with and experimenting on their own WebRTC projects. Which in turn, further develops the SimpleWebRTC and global WebRTC open source communities.&lt;/p&gt;
&lt;h2 id=&quot;what-do-you-think&quot;&gt;&lt;a href=&quot;#what-do-you-think&quot; aria-label=&quot;what do you think permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What do you think?&lt;/h2&gt;
&lt;p&gt;We’d love to hear from you about all of this. Please feel free to reach out to us on &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;Twitter&lt;/a&gt;, &lt;a href=&quot;http://facebook.com/andyetis&quot;&gt;Facebook&lt;/a&gt;, and &lt;a href=&quot;mailto:contact@andyet.com&quot;&gt;via email&lt;/a&gt;. (Heck, you could even let us know on &lt;a href=&quot;https://www.linkedin.com/company/&amp;#x26;yet&quot;&gt;LinkedIn&lt;/a&gt;!)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can help us spread the word!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The vast majority of web users have never heard of Talky. &lt;strong&gt;Help us spread the word. The #1 most valuable thing you could do to help us succeed with this Kickstarter and with Talky in general is to use it, talk about it, and share it.&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;We’d be honored to have your support. &lt;/p&gt;
&lt;p&gt;Sign up below to learn more about Talky and the upcoming Kickstarter!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[FluentConf talk: WebRTC and ORTC live together in perfect harmony?]]></title><description><![CDATA[Fippo and I gave a talk this week at Fluent covering:The basic fundamentals of WebRTCHow easy it is to get started building an app with…]]></description><link>https://blog.andyet.com/2015/04/22/webrtc-and-ortc/</link><guid isPermaLink="false">https://blog.andyet.com/2015/04/22/webrtc-and-ortc/</guid><pubDate>Wed, 22 Apr 2015 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://andyet.com/team/fippo&quot;&gt;Fippo&lt;/a&gt; and I gave a talk this week at &lt;a href=&quot;http://fluentconf.com/javascript-html-2015/public/schedule/detail/39541&quot;&gt;Fluent&lt;/a&gt; covering:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The basic fundamentals of WebRTC&lt;/li&gt;
&lt;li&gt;How easy it is to get started building an app with &lt;a href=&quot;http://simplewebrtc.com&quot;&gt;SimpleWebRTC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What &apos;signaling&apos; means &lt;/li&gt;
&lt;li&gt;Why IETF controversy over multiparty signaling led to &lt;a href=&quot;http://ortc.org&quot;&gt;ORTC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What&apos;s different about ORTC and why telephony engineers such as Fippo like it (and why web developers won&apos;t care)&lt;/li&gt;
&lt;li&gt;&amp;#x26;yet&apos;s future plans to support WebRTC and ORTC with SimpleWebRTC&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://andyet.com/team/gar&quot;&gt;Gar&lt;/a&gt; even was able to make a cameo appearance to kick off the talk with an acapella &lt;a href=&quot;https://www.youtube.com/watch?v=TZtiJN6yiik&quot;&gt;Stevie Wonder and Paul McCartney&lt;/a&gt; cover with some twisted lyrics:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WebRTC and ORTC
live together in perfect harmony
side by side on my laptop keyboard
Oh, Lord, hopefully...?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;http://fluent-ortc.surge.sh&quot;&gt;Here&apos;s the slides from the talk&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you to the Fluent staff who were great hosts and incredibly well organized.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[A frontend JavaScript framework to pair with Node.js]]></title><description><![CDATA[Node has changed the way we write applications at &yet. Not just sort of changed, in fact, if it didn’t sound so cliché I would use…]]></description><link>https://blog.andyet.com/2015/04/14/frontend-frameworks-to-pair-with-node/</link><guid isPermaLink="false">https://blog.andyet.com/2015/04/14/frontend-frameworks-to-pair-with-node/</guid><pubDate>Tue, 14 Apr 2015 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Node has changed the way we write applications at &amp;#x26;yet. Not just &lt;em&gt;sort of&lt;/em&gt; changed, in fact, if it didn’t sound so cliché I would use “revolutionized” to describe it.&lt;/p&gt;
&lt;p&gt;How so? Well, if I were forced to pare it down to a single word it’d be “modularity.”&lt;/p&gt;
&lt;p&gt;Annoyingly, the word “modular” doesn&apos;t really mean much. Of course &lt;em&gt;every developer&lt;/em&gt; strives to write modular code, so let’s disambiguate it a bit.&lt;/p&gt;
&lt;h2 id=&quot;modularity-across-applications&quot;&gt;&lt;a href=&quot;#modularity-across-applications&quot; aria-label=&quot;modularity across applications permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Modularity across applications&lt;/h2&gt;
&lt;p&gt;Within an application, splitting things into separate files with singular concerns is a great start. But as a &lt;a href=&quot;http://seaworthy.io&quot;&gt;Node consulting company&lt;/a&gt; we write lots of &lt;em&gt;different applications&lt;/em&gt; many of which share similar functionality. The logical next level of code reuse and modularity is being able to easily reuse code across applications as well.&lt;/p&gt;
&lt;p&gt;This isn’t a new idea, of course. In the case of Node, this is where &lt;a href=&quot;http://npmjs.org&quot;&gt;npm&lt;/a&gt; comes into play. It does a great job of limiting “dependency hell” that comes from different packages requiring different versions of the same dependencies, as made possible by adhering to &lt;a href=&quot;http://semver.org/&quot;&gt;semantic versioning&lt;/a&gt;. &lt;a href=&quot;https://twitter.com/maxogden&quot;&gt;Max Ogden&lt;/a&gt; wrote &lt;a href=&quot;http://maxogden.com/nested-dependencies.html&quot;&gt;a nice, quick explainer&lt;/a&gt; of nested dependencies à la npm.&lt;/p&gt;
&lt;p&gt;This means even really simple and small modules can be reused across applications and less unique code has to be generated for a given project. &lt;/p&gt;
&lt;p&gt;The net result is &lt;strong&gt;faster development cycles&lt;/strong&gt;, &lt;strong&gt;happier developers&lt;/strong&gt;, and &lt;strong&gt;lower total costs&lt;/strong&gt; for our clients. Modularity lets us put the bulk of our effort into the real problems the software we’re building aims to solve, instead of solving the same problems over and over.&lt;/p&gt;
&lt;p&gt;Development becomes more like building with &lt;strong&gt;Lego™&lt;/strong&gt; where you snap small pieces of functionality together to create something interesting. You’ve got pieces of various shapes, sizes and functionality that, when placed into the hands of talented developers, can be assembled into &lt;a href=&quot;http://powerpig.storenvy.com/&quot;&gt;incredibly diverse and amazing things&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cldup.com/ulCS-gpOl6-3000x3000.png&quot; alt=&quot;amazingly detailed lego refrigerator&quot;&gt;&lt;/p&gt;
&lt;p&gt;By contrast, larger toolsets feel more like &lt;strong&gt;Duplo™&lt;/strong&gt; blocks. They might get you there even quicker, but ultimately what’s created tends to feel clunky and less flexible. Great for prototyping, perhaps, but you simply lack the level of resolution required for creating a beautiful finished product that can very simply evolve over time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cldup.com/mTk9O-q6QK-3000x3000.png&quot; alt=&quot;duplo blocks&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;node-flavored-frontend-systems&quot;&gt;&lt;a href=&quot;#node-flavored-frontend-systems&quot; aria-label=&quot;node flavored frontend systems permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Node-flavored frontend systems&lt;/h2&gt;
&lt;p&gt;So what about browser code? &lt;/p&gt;
&lt;p&gt;Too often the wild west that is the frontend makes backend developers squirm. The seemingly infinite options of frameworks, module systems, package managers, and philosophies are often nothing short of discouraging.&lt;/p&gt;
&lt;p&gt;Historically, the frontend was fairly simple. You’d drop in &lt;code class=&quot;language-text&quot;&gt;&amp;lt;script src=&amp;quot;jquery.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;, do a few simple rollover effects, init some jQuery plugins and be happy. These days users expect a lot more. We’re treating the frontend &lt;a href=&quot;https://blog.andyet.com/2014/01/17/web-has-outgrown-the-browser&quot;&gt;as a runtime&lt;/a&gt; and we’re using it to build richly interactive &lt;a href=&quot;https://blog.andyet.com/2015/01/22/native-web-apps&quot;&gt;Native Web Apps&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Like it or not, more and more logic of web applications is being moved into the browser’s runtime. People from all manner of backend development perspectives are writing more frontend code. We’re all converging in the land o’ JavaScript, bringing all our various development philosophies and styles with us as we move that direction. This helps explain the plethora of tools, approaches, and styles we see on the frontend.&lt;/p&gt;
&lt;p&gt;Painting with broad strokes, we see that folks with a Rails background are drawn to &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember&lt;/a&gt;, folks from .NET, PHP, and Flex may feel more at home in &lt;a href=&quot;https://angularjs.org/&quot;&gt;Angular&lt;/a&gt;, and hardcore FRP-types are drawn to things like &lt;a href=&quot;https://github.com/omcljs/om&quot;&gt;Om&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But... &lt;/p&gt;
&lt;h2 id=&quot;what-do-node-people-do-on-the-frontend&quot;&gt;&lt;a href=&quot;#what-do-node-people-do-on-the-frontend&quot; aria-label=&quot;what do node people do on the frontend permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What do Node People™ do on the frontend?&lt;/h2&gt;
&lt;p&gt;Node devs tend to be minimalists, DIY&apos;ers, Lego™ artists, if you will. We want a nice set of tools and pieces at our disposal that we can compose into whatever creation we imagine. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cldup.com/r9h4JAGbx5.thumb.png&quot; alt=&quot;intricate lego computer&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you’ve bought into Node’s small module paradigm, stuff like Ember, Angular, and even jQuery can feel a bit like excessively large Duplo™ blocks. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To be clear, this doesn’t make them bad.&lt;/strong&gt; I’m glad they exist. Clearly, they empower scores of developers to create some great things on the frontend.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://browserify.org/&quot;&gt;Browserify&lt;/a&gt; certainly comes to mind. It lets you write code in the same CommonJS module format you’re used to from Node, run them through Browserify and have them &lt;em&gt;mostly&lt;/em&gt; Just Work™. Fellow Yeti &lt;a href=&quot;https://twitter.com/philip_roberts&quot;&gt;Philip Roberts&lt;/a&gt; wrote a great intro to &lt;a href=&quot;https://ampersandjs.com/learn/npm-browserify-and-modules&quot;&gt;npm, Browserify, and modules&lt;/a&gt; in the Ampersand.js user guides.&lt;/p&gt;
&lt;p&gt;If you’ve been around clientside development for a while you’ve certainly heard of &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt;. It shares a strong conceptual bond with Node, as seen in the following excerpt from Backbone’s docs: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Philosophically, Backbone is an attempt to discover the minimal set of data-structuring (models and collections) and user interface (views and URLs) primitives that are generally useful when building web applications with JavaScript. In an ecosystem where overarching, decides-everything-for-you frameworks are commonplace, and many libraries require your site to be reorganized to suit their look, feel, and default behavior — Backbone should continue to be a tool that gives you the freedom to design the full experience of your web application.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We see the same themes of freedom, flexibility, and do-it-yourself-ness common in the Node community. The only trouble is, from a structure perspective some of the bundling and coupling of Backbone diverges a bit from a totally npm-ified approach. We built on Backbone for a long time at &amp;#x26;yet. Eventually as &lt;a href=&quot;https://blog.andyet.com/2014/06/25/introducing-ampersand-js&quot;&gt;I’ve previously discussed&lt;/a&gt; these differences led us to extract/dissect/improve various components in Backbone and publish them all as individual modules on npm. For the sake of having unified name and documentation we called it &lt;a href=&quot;https://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;We’ve been thrilled to see so many of these modules used on their own and paired with all sort of other things. This is &lt;em&gt;precisely&lt;/em&gt; the sort of thing we were hoping for. We don’t want to build and maintain some giant monolithic framework and sell everyone on using it. &lt;/p&gt;
&lt;p&gt;Financial Times used &lt;a href=&quot;https://ampersandjs.com/docs#ampersand-state&quot;&gt;ampersand-state&lt;/a&gt; and &lt;a href=&quot;https://ampersandjs.com/docs#ampersand-view&quot;&gt;ampersand-view&lt;/a&gt; with &lt;a href=&quot;http://d3js.org/&quot;&gt;D3.js&lt;/a&gt; to create a &lt;a href=&quot;http://www.ft.com/ig/sites/2014/debt-to-gdp-ratio&quot;&gt;cool interactive debt-modeling&lt;/a&gt; tool using data from the IMF. &lt;/p&gt;
&lt;p&gt;WhatsApp’s new web app only uses a single Ampersand module (&lt;a href=&quot;http://ampersandjs.com/docs#ampersand-state&quot;&gt;amperand-state&lt;/a&gt;) and then the whole view layer is built with &lt;a href=&quot;http://reactjs.com/&quot;&gt;React&lt;/a&gt; components.&lt;/p&gt;
&lt;p&gt;For us, as long-term Node developers, seeing people mix and match our modules into their systems is a huge validation of our work of bringing the same modularized approaches we’ve fallen in love with on the backend to the frontend.&lt;/p&gt;
&lt;h2 id=&quot;so-whats-the-node-frontend-framework-of-choice-none&quot;&gt;&lt;a href=&quot;#so-whats-the-node-frontend-framework-of-choice-none&quot; aria-label=&quot;so whats the node frontend framework of choice none permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So what’s the Node frontend framework of choice? None.&lt;/h2&gt;
&lt;p&gt;Of course we think &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand modules&lt;/a&gt; are a great match for building frontends for our Node applications. But for Ampersand we use the term &quot;framework&quot; very loosely. As demonstrated by how people are using it, it&apos;s really is just a loosely coupled set of tools.&lt;/p&gt;
&lt;p&gt;In the end, the only constant in our field is &lt;strong&gt;change&lt;/strong&gt;. We simply cannot, in good conscience, assert that any single toolset (even our own) is the only valid approach. It’s just not how we think development should work.&lt;/p&gt;
&lt;p&gt;For a more detailed breakdown of several popular frameworks, read my &lt;a href=&quot;https://blog.andyet.com/2014/08/13/opinionated-rundown-of-js-frameworks&quot;&gt;Opinionated Rundown of JS Frameworks&lt;/a&gt; post.&lt;/p&gt;
&lt;h2 id=&quot;what-else-has-our-attention&quot;&gt;&lt;a href=&quot;#what-else-has-our-attention&quot; aria-label=&quot;what else has our attention permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What else has our attention?&lt;/h2&gt;
&lt;p&gt;Like you, we’re always intrigued by our ever-evolving craft, but we have a unique burden to carry. As a consulting company, we don’t just ship one product, we’re responsibile for shipping a lot of apps for a lot of different use cases and companies. As a result, we’re forced to keep our feet on the ground. We’re drawn to things that help us ship great stuff faster as a team.&lt;/p&gt;
&lt;p&gt;On the short-list of things that have our intense interest is &lt;a href=&quot;http://reactjs.com/&quot;&gt;React&lt;/a&gt;. While we have a nice Backbone-esque view-layer in &lt;a href=&quot;https://ampersandjs.com/docs#ampersand-view&quot;&gt;ampersand-view&lt;/a&gt; there are aspects of React that are extremely appealing in a view-layer and we’re increasingly building things that pair Ampersand with React and like what we see so far.&lt;/p&gt;
&lt;p&gt;Another is &lt;a href=&quot;http://webpack.github.io/&quot;&gt;WebPack&lt;/a&gt;. WebPack is an alternative to Browserify that also does a whole lot more. It can do most of what you might do with Browserify while also adding features from tools like &lt;a href=&quot;https://github.com/HenrikJoreteg/moonboots&quot;&gt;moonboots&lt;/a&gt;, &lt;a href=&quot;http://gruntjs.com/&quot;&gt;Grunt&lt;/a&gt;, &lt;a href=&quot;http://gulpjs.com/&quot;&gt;Gulp&lt;/a&gt;, etc. Essentially, it’s a very complete frontend build system in a nice, coherent, extensible package. It seems extremely stable and well supported. Of special interest is the &lt;a href=&quot;http://webpack.github.io/docs/webpack-dev-server.html&quot;&gt;WebPack Dev Server&lt;/a&gt; and the &lt;a href=&quot;http://gaearon.github.io/react-hot-loader/&quot;&gt;React Component Hot Loader&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-does-the-future-hold-for-the-frontend&quot;&gt;&lt;a href=&quot;#what-does-the-future-hold-for-the-frontend&quot; aria-label=&quot;what does the future hold for the frontend permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What does the future hold for the frontend?&lt;/h2&gt;
&lt;p&gt;Who knows?! But that doesn’t leave us powerless. Instead of trying to predict it, we try to build modular systems that are optimized for change. &lt;/p&gt;
&lt;p&gt;Also, if you liked this post, check out my book &lt;a href=&quot;http://humanjavascript.com/&quot;&gt;Human JavaScript&lt;/a&gt;. If not, you may prefer to tell me I’m wrong &lt;a href=&quot;https://twitter.com/HenrikJoreteg&quot;&gt;on Twitter&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Happy Internetmaking!  &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Remember the part earlier on about how we’re also a Node consulting company? It’s true &amp;#x26;yet has been helping Node developers from smaller teams to enterprise clients find custom solutions for their Node apps for the past five years.  &lt;/p&gt;
&lt;p&gt;Now, we’re making that a concentrated effort under the banner of &lt;a href=&quot;https://seaworthy.io&quot;&gt;Seaworthy&lt;/a&gt;, the lastest addition to the &amp;#x26;yet and &lt;a href=&quot;https://liftsecurity.io&quot;&gt;^lift security&lt;/a&gt; family.  &lt;/p&gt;
&lt;p&gt;Seaworthy puts you right in front of &amp;#x26;yet’s veteran team of end-to-end Node experts, offering support through &lt;strong&gt;Navigator Office Hours&lt;/strong&gt; and &lt;strong&gt;Lighthouse Architecture Audits&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Get in touch with our Seaworthy team ASAP to avoid sending out an SOS (sorry couldn’t resist the nautical pull) by visiting &lt;a href=&quot;https://seaworthy.io&quot;&gt;Seaworthy.io&lt;/a&gt; or contacting us via &lt;a href=&quot;https://seaworthy.io/#contact-form&quot;&gt;electronic mail&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Welcome Seaworthy to the &yet family!]]></title><description><![CDATA[&yet has long been a rambling crew of professionals.We love making products for clients, but we also love helping other teams solve…]]></description><link>https://blog.andyet.com/2015/04/10/welcome-seaworthy/</link><guid isPermaLink="false">https://blog.andyet.com/2015/04/10/welcome-seaworthy/</guid><pubDate>Fri, 10 Apr 2015 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;#x26;yet has long been a rambling crew of professionals.&lt;/p&gt;
&lt;p&gt;We love &lt;a href=&quot;http://andyet.com/product-development&quot;&gt;making products for clients&lt;/a&gt;, but we also love helping other teams solve particularly annoying problems or augmenting their talent with some of our focused expertise.&lt;/p&gt;
&lt;p&gt;In spite of our penchant for bleeding edge technologies, we have an extremely veteran crew. Most of our engineers are more than halfway through their second decade in the software field, quite a few starting their third—and some longer than that.&lt;/p&gt;
&lt;p&gt;When we set out to build a security consulting offering, we did so by creating a distinct division: &lt;a href=&quot;http://liftsecurity.io&quot;&gt;^lift security&lt;/a&gt;. ^lift has gone on to be a fixture of the Node community, leading the way in all things security.&lt;/p&gt;
&lt;p&gt;Today we’ve decided to follow the same path concerning a specific set of our consulting offerings. Node, frontend (JS, native web apps, and modular CSS), and Ops consulting services will be delivered by &lt;a href=&quot;http://seaworthy.io&quot;&gt;Seaworthy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/seaworthy_logo.svg&quot; alt=&quot;Seaworthy logo&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Seaworthy is all about helping you deliver ship-shape software.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most important of all in this? &lt;strong&gt;We want to talk to you.&lt;/strong&gt; We want to find out the challenges you’re experiencing and how we can help. So we’re launching an entirely new effort to kick this off: a series of online seminars and a new architectural audit service.&lt;/p&gt;
&lt;p&gt;Introducing &lt;em&gt;Navigator Office Hours&lt;/em&gt; and &lt;em&gt;Lighthouse Audits&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;navigator-office-hours&quot;&gt;&lt;a href=&quot;#navigator-office-hours&quot; aria-label=&quot;navigator office hours permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Navigator Office Hours&lt;/h2&gt;
&lt;p&gt;A few times a month, one or two of our experts will be hosting office hours. These are limited space sessions sharing from our experience and answering your questions.&lt;/p&gt;
&lt;p&gt;First up, Henrik Joreteg will be talking about Native Web Apps, focusing on building modern JavaScript applications with &lt;a href=&quot;http://ampersandjs.com&quot;&gt;Ampersand&lt;/a&gt; and &lt;a href=&quot;https://facebook.github.io/react/&quot;&gt;React&lt;/a&gt;. Space is limited, &lt;a href=&quot;https://ti.to/seaworthy/navigator-office-hours-with-henrik-joreteg&quot;&gt;sign up now!&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;lighthouse-audits&quot;&gt;&lt;a href=&quot;#lighthouse-audits&quot; aria-label=&quot;lighthouse audits permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lighthouse Audits&lt;/h2&gt;
&lt;p&gt;With our new audit service, we’ll dive deep into your code, have some long conversations about your goals, and help you chart a course to getting your software ship-shape. You’ll get our most seasoned veterans’ perspective on your work and be able to apply our team’s best thinking to your problems. These audits can be focused on software architecture, frontend JS, UX, or modular CSS.&lt;/p&gt;
&lt;p&gt;So that’s Seaworthy.&lt;/p&gt;
&lt;p&gt;We’re happy to add this to the &amp;#x26;yet family of offerings. We get a lot of joy out of helping other teams with their challenges and we’re looking forward to writing a lot more boat-related puns.&lt;/p&gt;
&lt;p&gt;No, but seriously: you have no idea how many awesome boat puns there are until you write marketing copy for a nautical themed brand. You could even say there’s a boatload.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Kaiwa & Otalk: An open source love story]]></title><description><![CDATA[Earlier today our friends at Digicoop released Kaiwa, a great new text chat app for the web with a super-friendly user experience. We’re…]]></description><link>https://blog.andyet.com/2015/04/08/kaiwa-otalk/</link><guid isPermaLink="false">https://blog.andyet.com/2015/04/08/kaiwa-otalk/</guid><pubDate>Wed, 08 Apr 2015 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Earlier today our friends at &lt;a href=&quot;https://github.com/digicoop&quot;&gt;Digicoop&lt;/a&gt; released &lt;a href=&quot;http://getkaiwa.com/&quot;&gt;Kaiwa&lt;/a&gt;, a great new text chat app for the web with a super-friendly user experience. We’re keen on the fact it&apos;s built on top of some of the open source code we’ve been working on for years, such as the &lt;a href=&quot;https://github.com/otalk/stanza.io&quot;&gt;Stanza.io&lt;/a&gt; library for XMPP in JavaScript.  &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/kaiwa_logo.png&quot; alt=&quot;Kaiwa logo&quot;&gt;&lt;/p&gt;
&lt;p&gt;Yeti &lt;a href=&quot;http://andyet.com/team/lance&quot;&gt;Lance Stout&lt;/a&gt; created a prototype application called &lt;a href=&quot;https://otalk.im/&quot;&gt;Otalk.im&lt;/a&gt; along these lines a while back (as demonstrated at &lt;a href=&quot;https://vimeo.com/77289728&quot;&gt;RealtimeConf 2013&lt;/a&gt; starting around 16:45), and through the beauty of open source software the Digicoop team forked &lt;a href=&quot;https://github.com/otalk/otalk-im-client&quot;&gt;that code&lt;/a&gt; as the foundation for Kaiwa. &lt;/p&gt;
&lt;p&gt;Congratulations, Digicoop!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[And the WebRTC Platform of the Year Award goes to... Chrome!]]></title><description><![CDATA[Recently, Chrome’s WebRTC product manager, Serge Lachapelle, asked a critical question about WebRTC “product of the year” awards:We agree…]]></description><link>https://blog.andyet.com/2015/04/08/and-the-webrtc-platform-award-goes-to/</link><guid isPermaLink="false">https://blog.andyet.com/2015/04/08/and-the-webrtc-platform-award-goes-to/</guid><pubDate>Wed, 08 Apr 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, Chrome’s WebRTC product manager, &lt;a href=&quot;https://twitter.com/webrtc&quot;&gt;Serge Lachapelle&lt;/a&gt;, asked a critical question about WebRTC “product of the year” awards:&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;I see all these webrtc product of the year awards... And here I am wondering how come Chrome has not won one yet.&lt;/p&gt;&amp;mdash; Serge Lachapelle (@slac) &lt;a href=&quot;https://twitter.com/slac/status/580712622112292864&quot;&gt;March 25, 2015&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;We agree!&lt;/p&gt;
&lt;p&gt;Without all the hard work by the Chrome, Firefox, and Opera teams, WebRTC would not exist, nor could we build applications like &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;WebRTC is by far the most complex feature ever added to web browsers, and we believe it to be an important technology for the present and future of the Open Web.&lt;/p&gt;
&lt;p&gt;We’re extremely grateful for the work of standards authors, and for the hard work of Chrome, Firefox, and Opera teams in creating quality platforms that make it possible to build web applications with peer-to-peer voice, video, and data — many of which are reliably interoperable.&lt;/p&gt;
&lt;p&gt;Most of these folks do their work on these technologies with minimal thanks or accolades from users or businesses who rely on them. Our hats are off to each one of them!&lt;/p&gt;
&lt;p&gt;Over the years of working with WebRTC, we’ve had a lot of interactions with the Chrome and Firefox teams (and for the record, a member of the Opera team also &lt;a href=&quot;https://plus.google.com/+WebRTCorg/posts/B4GdTd6aMEE&quot;&gt;fixed a bug I filed recently&lt;/a&gt;). They’ve all been great to work with - and they care, as we do, about making realtime communication technologies friendly for web developers.&lt;/p&gt;
&lt;p&gt;But above any other, it’s clear to us that one platform has contributed more to the WebRTC ecosystem - Google Chrome.&lt;/p&gt;
&lt;p&gt;Here’s why:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;According to our internal stats, 85% of Talky users choose Chrome.&lt;/li&gt;
&lt;li&gt;The quality is awesome and feature set is far ahead of the curve. Our team uses and relies on it for small group conversations daily and it’s the only option that has enough features to support our weekly team meetings. &lt;/li&gt;
&lt;li&gt;The Chrome team’s response to critical bug reports is awesome, as explained in &lt;a href=&quot;https://blog.andyet.com/2015/01/30/chrome-update-killed-the-webrtc-star&quot;&gt;“Chrome update killed the WebRTC star.”&lt;/a&gt; Also, their bug report process works really well.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://webrtc.org&quot;&gt;WebRTC.org Library&lt;/a&gt; is widely used to power apps on mobile devices, such as our Talky iOS app.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In recognition of the above work and for their contributions towards WebRTC, we are pleased to acknowledge them as the “WebRTC Platform of the Year.”&lt;/p&gt;
&lt;p&gt;&lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 129.13907284768212%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAaCAIAAAA44esqAAAACXBIWXMAAAsSAAALEgHS3X78AAADEUlEQVQ4y5VT3UtTYRjfXxFdiIkUSqiZRARGEBQRaIIXURDdFBVdpTfemHgblBUYCCHW2Zz7sOZHc+jQoU1ym+TmVNQ2z3u295x5tp2dfeu2c97Tuw8r82Pzx8PD8zy8v/2ejx3ZEsko7FDhgANLXqUjG+B00HGc4WeEHVrcjAy/LpOTl7VU8xisHCRr1KBeQ1UrQZWSrB7KeSXAQa4CqrIVcH4IlMvBeyvMki+pKd1G1Munnhl9t8fh8zm2TgUaNKBWBS6os1arIrGvz8UXNaBORZ4bBL02KMMNNGo9IJSSJOmNhbs7yfQ6+Q9Ovs3s77IGOy2BHnvo1U+u2xpsn/e/tARemNm+Ff7GOHxr8crwDLilLrP/nY1r1cNGnefeJHN/yndrHN6ZoJv1sGWCbtLTOL2m89wc81796mk10GcHydcLXpncDisU5Bliq+yzu0K+VU64T39ynxpwlRNblfKtaiVZoyIbNNSVL9T1EW+THj4wMk9N2x0LwWmXX6ZbZVoM9BPTdruZ7bYFe+x8/1pE64oZPHGzL+kI7roj6e2kkMggaT8SsaiM4/n/y8cCP/bFs78UjkRlPM/nSwhJYs6EPRP3DGEIGezwy4yI+lf4WBrFY3vkYmoI/aO8MwNQUojGYyWRpXRaWrYiLpLPdrTrUiITKUpGooj98jQx9+hxwNApZYeQdnQbmHyIMspBFMV8IIgCLn509j3UdgR/tUlSKkv+egT54LTZq4i7ZNwkIbbQ9kHl/DIBALOzs+b5+cXFRafTuba2NmU0mqZn5kw/vpsX8os7RFnMjedwOAiCGBkdHR4eNplMNptNrlAQcrlao9LrvxWUS2z74DqOIxf2JAjYsyzrcrnwIB6PhyRJiqLy3RVRTiQSm5ubEELMpGmaYRjM9/l8xcn53jiOwxxvDphPAYrxMaKISp157+aFUf/gyD/JIR8RRiy1E0iGxUJaKlkQxIyEBBhZn6dXY2kJoROcKp5IsKyfi4S5aDgSChVO9Vc5HJZOiN3h9QLZ7/eHjwa/3/LgHFQ4GAoEA78BLVtg4m94kVAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;the actual award&quot;
        title=&quot;&quot;
        src=&quot;/static/a63af17adaf9b738e9155cdd06f0da36/90cbd/webrtc-award.png&quot;
        srcset=&quot;/static/a63af17adaf9b738e9155cdd06f0da36/29fe9/webrtc-award.png 151w,
/static/a63af17adaf9b738e9155cdd06f0da36/6728c/webrtc-award.png 303w,
/static/a63af17adaf9b738e9155cdd06f0da36/90cbd/webrtc-award.png 605w,
/static/a63af17adaf9b738e9155cdd06f0da36/8c76f/webrtc-award.png 612w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The award features both the WebRTC and Chrome logos - the combination of technology and platform we want to recognize with this honor. What’s that little rocket? It’s a small, but beloved part of Talky, included to remind us how Talky is made possible by the work of the Google team. And of course, the award is certified by &lt;a href=&quot;https://andyet.com&quot;&gt;&amp;#x26;yet&lt;/a&gt;, a company. &lt;/p&gt;
&lt;p&gt;Who needs permission to give awards? We sure don’t.&lt;/p&gt;
&lt;p&gt;With that, we&apos;re proud to congratulate the Chrome team on winning the 2015 WebRTC Platform of the Year Award!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Postgres’s publish-subscribe features made better with JSON]]></title><description><![CDATA[If you need a database feature, Postgres probably has it.Recently, in versions 9.3 and 9.4, the Postgres devs have added JSON support in the…]]></description><link>https://blog.andyet.com/2015/04/06/postgres-pubsub-with-json/</link><guid isPermaLink="false">https://blog.andyet.com/2015/04/06/postgres-pubsub-with-json/</guid><pubDate>Mon, 06 Apr 2015 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you need a database feature, &lt;a href=&quot;http://www.postgresql.org/&quot;&gt;Postgres&lt;/a&gt; probably has it.&lt;/p&gt;
&lt;p&gt;Recently, in versions 9.3 and 9.4, the Postgres devs have added JSON support in the form of JSON types, functions, and operators.&lt;/p&gt;
&lt;p&gt;JSON functionality ends up being pretty handy for REST APIs, which I will get into in a later post, but it also has some other uses.&lt;/p&gt;
&lt;p&gt;You may not have known this, but Postgres has Publish-Subscribe functionality in the form of &lt;a href=&quot;http://www.postgresql.org/docs/9.4/static/sql-notify.html&quot;&gt;NOTIFY, LISTEN, UNLISTEN&lt;/a&gt;. This is commonly used for sending notifications that table rows have changed.&lt;/p&gt;
&lt;p&gt;Unfortunately, the &lt;code class=&quot;language-text&quot;&gt;NOTIFY&lt;/code&gt; payload is merely text, meaning that structured data will need to be encoded somehow.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;json_build_object&lt;/code&gt; to the rescue!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sql&quot;&gt;&lt;pre class=&quot;language-sql&quot;&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;FUNCTION&lt;/span&gt; table_update_notify&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;RETURNS&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;trigger&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;AS&lt;/span&gt; $$
&lt;span class=&quot;token keyword&quot;&gt;DECLARE&lt;/span&gt;
  id &lt;span class=&quot;token keyword&quot;&gt;bigint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt; TG_OP &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;INSERT&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;OR&lt;/span&gt; TG_OP &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;UPDATE&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;THEN&lt;/span&gt;
    id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;ELSE&lt;/span&gt;
    id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; OLD&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  PERFORM pg_notify&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;table_update&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; json_build_object&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;table&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TG_TABLE_NAME&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;type&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TG_OP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;::&lt;span class=&quot;token keyword&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;RETURN&lt;/span&gt; NEW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
$$ &lt;span class=&quot;token keyword&quot;&gt;LANGUAGE&lt;/span&gt; plpgsql&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; users_notify_update &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; users&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; users_notify_update &lt;span class=&quot;token keyword&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; users &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PROCEDURE&lt;/span&gt; table_update_notify&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; users_notify_insert &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; users&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; users_notify_insert &lt;span class=&quot;token keyword&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; users &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PROCEDURE&lt;/span&gt; table_update_notify&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;DROP&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; users_notify_delete &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; users&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;TRIGGER&lt;/span&gt; users_notify_delete &lt;span class=&quot;token keyword&quot;&gt;AFTER&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;ON&lt;/span&gt; users &lt;span class=&quot;token keyword&quot;&gt;FOR EACH ROW&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;EXECUTE&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;PROCEDURE&lt;/span&gt; table_update_notify&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here we’ve created a stored-procedure that is meant to be called from a &lt;a href=&quot;http://www.postgresql.org/docs/9.4/static/sql-createtrigger.html&quot;&gt;TRIGGER&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since some operations exclusively populate &lt;code class=&quot;language-text&quot;&gt;NEW&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;OLD&lt;/code&gt; row objects, this stored procedure checks for that with an IF/ELSE statement.&lt;/p&gt;
&lt;p&gt;Then it simply runs &lt;code class=&quot;language-text&quot;&gt;pg_notify&lt;/code&gt; to a channel with a &lt;code class=&quot;language-text&quot;&gt;json_build_object&lt;/code&gt; to compose the JSON for structured data.
Then we create a trigger for each operation for a given table, mapping it to our stored procedure.&lt;/p&gt;
&lt;p&gt;Now we can use &lt;a href=&quot;http://www.postgresql.org/docs/9.4/static/sql-listen.html&quot;&gt;LISTEN&lt;/a&gt; in our language of choice, and parse the payload we created as JSON.&lt;/p&gt;
&lt;p&gt;Here is a quick example in Node.js:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; pg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;pg&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

pg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;postgres://localhost/fritzy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; client&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;notification&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;notification&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;channel &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;table_update&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; pl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;*========*&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pl&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-========-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;LISTEN table_update&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, I’m iterating through the object, simply to show that it is structured.&lt;/p&gt;
&lt;p&gt;Now, regardless of where your &lt;code class=&quot;language-text&quot;&gt;TRIGGER&lt;/code&gt; assigned table is changed, you’ll receive JSON updates when you &lt;code class=&quot;language-text&quot;&gt;LISTEN&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;gt; INSERT INTO users (username) values (&amp;#39;fritzy&amp;#39;);

*========*
type INSERT
id 1
table users
-========-

&amp;gt; UPDATE users SET email=&amp;#39;fritzy@andyet.com&amp;#39; WHERE id=1;

*========*
type UPDATE
id 1
table users
-========-

&amp;gt; DELETE FROM users WHERE id=1;

*========*
type DELETE
id 1
table users
-========-&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;other-use-cases&quot;&gt;&lt;a href=&quot;#other-use-cases&quot; aria-label=&quot;other use cases permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Other Use Cases&lt;/h2&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; interesting! Is there a way to get the actual change data? (a la CouchDB)&lt;/p&gt;&amp;mdash; Pe̛dr͘o̧ Tèi͜xei҉r͞ (@pgte) &lt;a href=&quot;https://twitter.com/pgte/status/585138902148722690&quot;&gt;April 6, 2015&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;Yeah Pedro, there’s quite a bit we can do with the &lt;code class=&quot;language-text&quot;&gt;NEW&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;OLD&lt;/code&gt; rows in a trigger.&lt;/p&gt;
&lt;p&gt;If you’d like to send the entire row, you can do something like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;pg_notify(&amp;#39;table_update&amp;#39;, row_to_json(NEW)::text);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Or even&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;pg_notify(json_build_object(&amp;#39;table&amp;#39;, TG_TABLE_NAME, &amp;#39;id&amp;#39;, id, &amp;#39;type&amp;#39;, TG_OP, &amp;#39;row&amp;#39;, row_to_json(NEW))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But remember that you’ll want to check the operation to make sure whether to use &lt;code class=&quot;language-text&quot;&gt;NEW&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;OLD&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you wanted to get really fancy, you could create a DIFF from the &lt;code class=&quot;language-text&quot;&gt;OLD&lt;/code&gt; row to &lt;code class=&quot;language-text&quot;&gt;NEW&lt;/code&gt; row on updates, and create a change feed like &lt;a href=&quot;http://couchdb.apache.org/&quot;&gt;CouchDB&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;en&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; so i was thinking about using pg_notify() last week, but you introduce entropy into the system when the listening agent fails&lt;/p&gt;&amp;mdash; Tom Santero (@tsantero) &lt;a href=&quot;https://twitter.com/tsantero/status/585148788026802177&quot;&gt;April 6, 2015&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;Good point, Tom. What if you are depending on reliable messaging for something like invalidating a cache?
If your listening process flakes out, you’d be in trouble.&lt;/p&gt;
&lt;p&gt;You could mitigate this risk by INSERTing into a log table for your INSERT/UPDATE/DELETE triggers, and NOTIFYing on INSERT to your log table instead.&lt;/p&gt;
&lt;p&gt;Then, when your LISTEN-cache-invalidate process reconnects, it can check the log table for missed messages. You could use the JSON or JSONB type in your log table for easy parsing.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Please let me know via &lt;a href=&quot;mailto:fritzy@andyet.com&quot;&gt;Email&lt;/a&gt; or &lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;Twitter @fritzy&lt;/a&gt; if you have any questions or thoughts.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The real case for digital security: meet the ISC Project]]></title><description><![CDATA[Software should solve real-world human problems, and the most important problems will probably be the hardest. Nowhere is this more apparent…]]></description><link>https://blog.andyet.com/2015/04/03/digital-security/</link><guid isPermaLink="false">https://blog.andyet.com/2015/04/03/digital-security/</guid><pubDate>Fri, 03 Apr 2015 13:46:00 GMT</pubDate><content:encoded>&lt;p&gt;Software should solve real-world human problems, and the most important problems will probably be the hardest. &lt;/p&gt;
&lt;p&gt;Nowhere is this more apparent than when developers come face to face with people who depend on a software app for their lives.&lt;/p&gt;
&lt;p&gt;I am currently attending the &lt;a href=&quot;https://iscproject.org/&quot;&gt;ISC Project&apos;s&lt;/a&gt; Global Workshop, which brings together technologists and activists from all over the world. Most of the attendees are activists from different communities across the globe fighting for human rights, political freedom, and independent media. All of them use technology to advance their work, but the choice of &lt;em&gt;which&lt;/em&gt; tool to use requires vastly different criteria than societally privileged people typically consider.&lt;/p&gt;
&lt;p&gt;Most of us answer &quot;Which tool should I use?&quot; based on some pretty simple criteria: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is it well designed?&lt;/li&gt;
&lt;li&gt;Is it fast and reliable?&lt;/li&gt;
&lt;li&gt;How much does it cost? &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Imagine needing to answer &lt;em&gt;these questions&lt;/em&gt; before you even considered your normal usability ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can I trust the developers of this software and their company?&lt;/li&gt;
&lt;li&gt;Will this app leak or sell my data?&lt;/li&gt;
&lt;li&gt;How will this app hold up to surveillance?&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Can I trust this app with my life?&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&apos;ve been talking to folks here at the Global Workshop about &lt;a href=&quot;https://beta.talky.io&quot;&gt;Talky&lt;/a&gt;, our no-plugin, browser-based video chat app.&lt;/p&gt;
&lt;p&gt;There&apos;s a real need for Talky in the world of global activism, but answering these tough questions about our app – knowing that someone could be trusting their life with your software – is not something to be taken lightly. (Nor is it something that we do take lightly!)&lt;/p&gt;
&lt;p&gt;Privacy and openness are core tenets of our company, but the critical need was underscored heavily by meeting Talky users who truly understand the implications of surveillance and closed-door technologies. Let&apos;s stand with them as a developer community, and strive to do right by them.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Building Native Web Applications at Fluent Conf 2015]]></title><description><![CDATA[A training storyIn three weeks, the &yet training team is excited to lead Fluent Conf 2015 attendees in three training sessions covering…]]></description><link>https://blog.andyet.com/2015/04/02/fluent-conf-native-web-apps/</link><guid isPermaLink="false">https://blog.andyet.com/2015/04/02/fluent-conf-native-web-apps/</guid><pubDate>Thu, 02 Apr 2015 17:36:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;a-training-story&quot;&gt;&lt;a href=&quot;#a-training-story&quot; aria-label=&quot;a training story permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A training story&lt;/h2&gt;
&lt;p&gt;In three weeks, the &amp;#x26;yet training team is excited to lead &lt;a href=&quot;http://fluentconf.com/javascript-html-2015&quot;&gt;Fluent Conf 2015&lt;/a&gt; attendees in three training sessions covering subjects like Native Web Application development, Node.js security, and WebRTC. One of our latest training offerings is &lt;a href=&quot;http://fluentconf.com/javascript-html-2015/public/content/native-web-application&quot;&gt;Building Native Web Applications&lt;/a&gt;, led by Henrik Joreteg and Luke Karrys.  &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/luke_training.JPG&quot; alt=&quot;Luke leading a training class. Photo credit: Jenna Tormanen&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://andyet.com/team/henrik&quot;&gt;Henrik&lt;/a&gt;, prolific module creator, is a foremost developer tackling the subject of Native Web Applications (aka Single Page Apps) in the JavaScript community. He has pioneered many techniques for building stateful JavaScript applications, especially those with a realtime aspect. &lt;/p&gt;
&lt;p&gt;Most recently, he leads development on the &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt; framework, which has seen rapid adoption among many prominent Backbone.js developers. Henrik also created the &lt;a href=&quot;http://simplewebrtc.com/&quot;&gt;SimpleWebRTC library&lt;/a&gt;, &lt;a href=&quot;https://talky.io/&quot;&gt;Talky.io&lt;/a&gt;, is the author of the book &lt;a href=&quot;http://read.humanjavascript.com/&quot;&gt;“Human JavaScript”&lt;/a&gt;, and frequently speaks at JS events, including &lt;a href=&quot;http://fluentconf.com/javascript-html-2015/public/schedule/detail/42405&quot;&gt;this year’s Fluent Conf&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://andyet.com/team/luke&quot;&gt;Luke&lt;/a&gt;, a high quality Node.js front-end developer, also leads development on Ampersand.js as a core contributor.  Additionally, he’s a veteran instructor of &amp;#x26;yet’s intense and immersive “Human JavaScript: Live” training endeavor. He recently participated in the creation of the ultimate project: a newborn daughter.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://fluentconf.com/javascript-html-2015/public/content/native-web-application&quot;&gt;course description&lt;/a&gt; states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Henrik and Luke will lead the course in building a modern, well-structured application from scratch by combining first class approaches and a carefully curated set of tools including:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ampersand.js:&lt;/strong&gt; A highly modular set of libraries for building Advanced JavaScript apps.&lt;br&gt;
&lt;strong&gt;React:&lt;/strong&gt; Facebook’s revolutionary view library.&lt;br&gt;
&lt;strong&gt;WebPack:&lt;/strong&gt; Module bundler and development server.&lt;br&gt;
&lt;strong&gt;ES6:&lt;/strong&gt; The next generation of the JavaScript language.&lt;br&gt;
&lt;strong&gt;Node.js:&lt;/strong&gt; The JavaScript platform built on Chrome’s runtime. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But what can else can attendees expect?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Henrik Joreteg:&lt;/strong&gt; Rather than just theory and buzzwords attendees will build and deploy an application from scratch against a real third-party API and auth system (GitHub’s) and accidentally become familiar with some new, powerful tools in the process.  So many people are overwhelmed with the plethora of frontend tools available. The goal is to leave people feeling empowered, building something real, and not add to that confusion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Luke Karrys:&lt;/strong&gt; Building a real live working application is often the best way to learn new tools and paradigms. Add in instructors to answer all your questions and walk you through the challenging aspects, and this training will provide the perfect platform to get up to speed with some of the best and most powerful tools and concepts in frontend development today.  &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/henrik_training.jpg&quot; alt=&quot;Henrik during a recent training. Photo credit: Jenna Tormanen&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our team is excited to share a training experience like “Building Native Web Applications” with Fluent Conf this year. This particular course has been two years in the making, and includes a lot of the principles and practices that &amp;#x26;yet has been teaching to clients for years.&lt;/p&gt;
&lt;h2 id=&quot;other-yet-courses-at-fluent&quot;&gt;&lt;a href=&quot;#other-yet-courses-at-fluent&quot; aria-label=&quot;other yet courses at fluent permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Other &amp;#x26;yet courses at Fluent&lt;/h2&gt;
&lt;p&gt;If you’re attending Fluent Conf, we’re also guiding two other trainings. &amp;#x26;yet CSO and &lt;a href=&quot;https://liftsecurity.io/team/baldwin&quot;&gt;^lift security lead Adam Baldwin&lt;/a&gt; and &lt;a href=&quot;http://andyet.com/team/gar&quot;&gt;requireSafe developer Michael Garvin&lt;/a&gt; are teaching &lt;a href=&quot;http://fluentconf.com/javascript-html-2015/public/content/node-js&quot;&gt;Securing Node.js Apps&lt;/a&gt;, based on the popular &lt;a href=&quot;https://liftsecurity.io/training&quot;&gt;Node Security Training&lt;/a&gt;, which focuses on building, exploiting, and fixing security issues in the most used Node.js frameworks, templating engines and database drivers.&lt;/p&gt;
&lt;p&gt;The other training is “Creating Production-Ready WebRTC Applications,” led by prominent &lt;a href=&quot;http://andyet.com/team/fippo&quot;&gt;WebRTC expert, Philipp “Fippo” Hancke&lt;/a&gt; and &lt;a href=&quot;http://andyet.com/team/david&quot;&gt;peer to peer applications master scholar David Dias&lt;/a&gt;. This latest &amp;#x26;yet training offering begins at the start of WebRTC technology, touching on browser compatibility, and covering all the elements you need to create a realtime communications app.&lt;/p&gt;
&lt;p&gt;For more information on Fluent Conf trainings or to register, go to &lt;a href=&quot;http://fluentconf.com/javascript-html-2015&quot;&gt;fluentconf.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more on &amp;#x26;yet training, including custom-tailored training for your team’s needs, reach out at &lt;a href=&quot;http://andyet.com/training&quot;&gt;andyet.com/training&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Improved Screensharing UX on Talky]]></title><description><![CDATA[User experience is very important to us. Almost a year ago, Chrome changed the way screensharing works in WebRTC in a way that increased the…]]></description><link>https://blog.andyet.com/2015/03/30/talky-first-time-ux-matters/</link><guid isPermaLink="false">https://blog.andyet.com/2015/03/30/talky-first-time-ux-matters/</guid><pubDate>Mon, 30 Mar 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;User experience is very important to us. Almost a year ago, Chrome changed the way screensharing works in WebRTC in a way that increased the usage for &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; by 300%. Still, the onboarding process for your first screen share was not as nice as it could have been.&lt;/p&gt;
&lt;p&gt;It used to be, if you tried to share your screen, you were required to install an extension. Once that extension was installed, you would have to reload Talky before you could share your screen. Until today, it was also necessary to click the &quot;Share Screen&quot; button again after the reload. &lt;/p&gt;
&lt;p&gt;Now, after you&apos;ve installed the extension, you&apos;re able to screenshare immediately, making the first-time experience faster and easier.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Amp’ed Down?]]></title><description><![CDATA[Hi! Remember this post introducing amp?Unsurprisingly, JDD from the lodash project took notice. All things said and done, he made sure that…]]></description><link>https://blog.andyet.com/2015/03/25/amped-down/</link><guid isPermaLink="false">https://blog.andyet.com/2015/03/25/amped-down/</guid><pubDate>Wed, 25 Mar 2015 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hi! Remember &lt;a href=&quot;http://blog.andyet.com/2015/01/07/modularizing-underscorejs&quot;&gt;this post introducing amp?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Unsurprisingly, JDD from &lt;a href=&quot;https://lodash.com/&quot;&gt;the lodash project&lt;/a&gt; &lt;a href=&quot;https://github.com/AmpersandJS/amp/issues/2#issuecomment-73199058&quot;&gt;took notice&lt;/a&gt;. All things said and done, he made sure that in the &lt;code class=&quot;language-text&quot;&gt;3.0.0&lt;/code&gt; release they addressed all the concerns I mentioned in that post, which is great!&lt;/p&gt;
&lt;p&gt;Specifically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Individually published, and &lt;a href=&quot;http://semver.org/&quot;&gt;semver&lt;/a&gt; versioned modules. This was the big one.&lt;/li&gt;
&lt;li&gt;Shallower dependency trees.&lt;/li&gt;
&lt;li&gt;Memorable names and not having to remember folder structure. All the functions are now available on npm as &lt;code class=&quot;language-text&quot;&gt;lodash.*&lt;/code&gt; where &lt;code class=&quot;language-text&quot;&gt;*&lt;/code&gt; is the function name. So, you can now just &lt;code class=&quot;language-text&quot;&gt;npm i lodash.bind&lt;/code&gt; for example.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;so-now-what-about-amp&quot;&gt;&lt;a href=&quot;#so-now-what-about-amp&quot; aria-label=&quot;so now what about amp permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So now what about &lt;a href=&quot;http://amp.ampersandjs.com/&quot;&gt;amp&lt;/a&gt;?&lt;/h2&gt;
&lt;p&gt;All of the amp modules that are duplicates of &lt;code class=&quot;language-text&quot;&gt;lodash.*&lt;/code&gt; modules, will no longer be maintained and a note has been added to each one on &lt;a href=&quot;http://amp.ampersandjs.com/&quot;&gt;the docs site&lt;/a&gt; with a link to the suggested lodash alternative.&lt;/p&gt;
&lt;p&gt;They won&apos;t be removed or deprecated on npm so if you started using them because you never wanted to think about or update them, worry not, they&apos;re still around. Lots of people are happily using those so there&apos;s no reason to take those down.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt; project will convert to using &lt;code class=&quot;language-text&quot;&gt;lodash.*&lt;/code&gt; modules. And we will continue to use &lt;a href=&quot;http://amp.ampersandjs.com/&quot;&gt;amp&lt;/a&gt; as a way to manage, test, and document utility modules that don&apos;t exist in lodash. This includes things like the DOM methods, etc.&lt;/p&gt;
&lt;p&gt;This is really all about time management. We see this as a good thing, Open Source FTW!&lt;/p&gt;
&lt;p&gt;Personally, I don&apos;t want to continue to spend my time or any of my teammates&apos; time duplicating efforts now that the initial concerns were all addressed.&lt;/p&gt;
&lt;p&gt;The lodash folks are doing an excellent job maintaining those utilities. Our hats are off to them.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[&yet & O’Reilly bring training to Fluent Conf 2015]]></title><description><![CDATA[We are excited to announce that in a month’s time, &yet is teaming up with O’Reilly to bring training to Fluent Conf 2015 in San Francisco…]]></description><link>https://blog.andyet.com/2015/03/24/fluent-conf-training/</link><guid isPermaLink="false">https://blog.andyet.com/2015/03/24/fluent-conf-training/</guid><pubDate>Tue, 24 Mar 2015 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We are excited to announce that in a month’s time, &amp;#x26;yet is teaming up with O’Reilly to bring training to &lt;a href=&quot;http://fluentconf.com/javascript-html-2015&quot;&gt;Fluent Conf 2015&lt;/a&gt; in San Francisco, California. &lt;/p&gt;
&lt;p&gt;On April 20–21, our training team will be leading &lt;a href=&quot;http://fluentconf.com/javascript-html-2015/public/schedule/full/public&quot;&gt;three cutting edge two-day sessions on native web applications, Node Security, and WebRTC&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/HenrikJoreteg&quot;&gt;Henrik Joreteg&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/lukekarrys&quot;&gt;Luke Karrys&lt;/a&gt;, creators and core maintainers of &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt;, will be teaching a course on &lt;a href=&quot;http://fluentconf.com/javascript-html-2015/public/content/native-web-application&quot;&gt;“Building Native Web Applications.”&lt;/a&gt; The focus of the course is building a modern, well-structured application from scratch by combining best-of approaches and a carefully curated set of tools including Ampersand.js, React, WebPack, ES6, and Node.js. (Read more about &lt;a href=&quot;https://blog.andyet.com/2015/01/22/native-web-apps&quot;&gt;our thoughts in Native Web Apps here&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://fluentconf.com/javascript-html-2015/public/content/node-js&quot;&gt;“Securing Node.js Apps”&lt;/a&gt; will be led by &lt;a href=&quot;https://liftsecurity.io/&quot;&gt;^lift security&lt;/a&gt; Team Lead &lt;a href=&quot;https://twitter.com/adam_baldwin&quot;&gt;Adam Baldwin&lt;/a&gt; with &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt; and &lt;a href=&quot;http://requiresafe.com/&quot;&gt;requireSafe&lt;/a&gt; developer &lt;a href=&quot;https://twitter.com/wraithgar&quot;&gt;Michael “Gar” Garvin&lt;/a&gt;. This popular &lt;a href=&quot;https://liftsecurity.io/training&quot;&gt;Node Security Training&lt;/a&gt; is a hands-on experience building, exploiting, and fixing security issues in the most used Node.js frameworks, templating engines and database drivers. &lt;/p&gt;
&lt;p&gt;As a 15 year veteran of realtime tech, &lt;a href=&quot;https://twitter.com/HCornflower&quot;&gt;Philipp “Fippo” Hancke&lt;/a&gt;, is not only &amp;#x26;yet&apos;s WebRTC lead, he&apos;s one of the world&apos;s leading WebRTC experts. He&apos;s also one of the leading non-Google contributors to the &lt;a href=&quot;http://www.webrtc.org/&quot;&gt;webrtc.org&lt;/a&gt; WebRTC library, which is used by Chrome, Opera, Google&apos;s iOS and Android WebRTC SDKs, and others. He&apos;ll be leading this new course, &lt;a href=&quot;http://fluentconf.com/javascript-html-2015/public/content/webrtc&quot;&gt;“Creating Production-Ready WebRTC Applications,”&lt;/a&gt; along with &lt;a href=&quot;https://twitter.com/daviddias&quot;&gt;David Dias&lt;/a&gt;, whose master thesis was on peer to peer applications. This latest training offering begins at the start of WebRTC technology, touching on browser compatibility, and covering all the elements you need to create a realtime communications app.&lt;/p&gt;
&lt;p&gt;For more information on Fluent Conf trainings or to register, go to &lt;a href=&quot;http://fluentconf.com/javascript-html-2015&quot;&gt;fluentconf.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more on &amp;#x26;yet training, including custom-tailored training for your team’s needs, reach out at &lt;a href=&quot;http://andyet.com/training&quot;&gt;andyet.com/training&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing Talky Beta]]></title><description><![CDATA[Today, we're announcing a public beta of the next generation of Talky - &yet's simple video chat and screensharing app for groups.And, in a…]]></description><link>https://blog.andyet.com/2015/03/19/introducing-talky-beta/</link><guid isPermaLink="false">https://blog.andyet.com/2015/03/19/introducing-talky-beta/</guid><pubDate>Thu, 19 Mar 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today, we&apos;re announcing a &lt;a href=&quot;https://beta.talky.io&quot;&gt;public beta of the next generation of Talky&lt;/a&gt; - &amp;#x26;yet&apos;s simple video chat and screensharing app for groups.&lt;/p&gt;
&lt;p&gt;And, in a few weeks, we&apos;ll be announcing a Kickstarter. But more on that later—first I want to tell you about what&apos;s new in the Talky beta.&lt;/p&gt;
&lt;p&gt;I hesitate to go all Jonny Ive on you, but seriously: the new version of Talky has been reconsidered, reengineered, and redesigned from the ground up. And everything we&apos;ve been building has been open sourced as part of &lt;a href=&quot;https://github.com/otalk&quot;&gt;Otalk&lt;/a&gt;, our open WebRTC platform.&lt;/p&gt;
&lt;h1 id=&quot;heres-the-key-improvements&quot;&gt;&lt;a href=&quot;#heres-the-key-improvements&quot; aria-label=&quot;heres the key improvements permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here&apos;s the key improvements&lt;/h1&gt;
&lt;p&gt;With the new Talky Beta, you&apos;ll be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Video chat with more participants than Google Hangouts.&lt;/li&gt;
&lt;li&gt;Have text chat conversations.&lt;/li&gt;
&lt;li&gt;Enjoy a new UI optimized for the way we have face-to-face group conversations, allowing you to make the face of each person in the discussion visible at all times and as large as possible. (We have more thoughts and plans in this direction, too!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find the next generation of Talky at &lt;a href=&quot;https://beta.talky.io&quot;&gt;beta.talky.io&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&apos;ve been using this version internally at &amp;#x26;yet for nearly 8 months and after many months of iteration, we feel it&apos;s ready to share with you.&lt;/p&gt;
&lt;p&gt;But this is still a &lt;em&gt;beta&lt;/em&gt;—for example, mobile support isn&apos;t there right now on any platform. (It&apos;s coming though!)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Talky Button]]></title><description><![CDATA[Firefox is starting to roll out Firefox Hello to more users. Hello is a videochat, very much like our own Talky.In the WebRTChacks analysiѕ…]]></description><link>https://blog.andyet.com/2015/02/26/hello-talky/</link><guid isPermaLink="false">https://blog.andyet.com/2015/02/26/hello-talky/</guid><pubDate>Thu, 26 Feb 2015 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Firefox is starting to roll out Firefox Hello to more users. Hello is a videochat, very much like our own &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://webrtchacks.com/hello-decode/&quot;&gt;WebRTChacks analysiѕ&lt;/a&gt;, I described it a small button to your browser that generates a call URL which you can share.&lt;/p&gt;
&lt;p&gt;A question by the &lt;a href=&quot;https://twitter.com/palavatv&quot;&gt;palava.tv&lt;/a&gt; team got me thinking:&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c703d69797f191c07e89a3967c610bbc/e17e5/palava-hello-question.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 400px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 50.331125827814574%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABfElEQVQoz41Sa3OCMBDk//+vzvRDO2OrYgKKgDyq9Y2QkBC2l/jsF8fM7NyF5PaWvXjrk4TuDNQjtEGrO8gnEEo72LylGm0MVpWApyj58Eu8DVIMih0+8y3e0y3Yb4Vnq6oqHGqJfHNCnCSQbYuj1PBq6rLZCyxWRyx3R5TbAx0o1K1G3/cOXddRxH1PIgxBtgpSdWiEdPt9o+AJKtwTQbitwUlVSODLA4rlGkmaIgxniKI54jhxkXGOWRQhL0pSlqIoipvqoyBC60Ge5/B5iDgrMWYBZvMUWV4gCKZgtA+nMwTh1JF8fQ8xnjBqtkBZ/mA0GkNr7QgFqfWsoVmWISIFvu9j7E+Q0mXOGPwJx5y+M8aRJFbt1JEPieRrOATnAeW+s8Su5kq4IIKY0JKxUkoo8vWa2+42t1Ep5SCEgKAzeYH19UZoTRXCPp0O5nJgDJmP19el7Exo/7ulaVV1g7oROFS1m975Yv8y/hH2NHJNwzEP8d69f0HhnfAPQHAA/RCAFwQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;It would be awesome if the Hello button could launch a palava tv call&quot;
        title=&quot;&quot;
        src=&quot;/static/c703d69797f191c07e89a3967c610bbc/e17e5/palava-hello-question.png&quot;
        srcset=&quot;/static/c703d69797f191c07e89a3967c610bbc/29fe9/palava-hello-question.png 151w,
/static/c703d69797f191c07e89a3967c610bbc/6728c/palava-hello-question.png 303w,
/static/c703d69797f191c07e89a3967c610bbc/e17e5/palava-hello-question.png 400w&quot;
        sizes=&quot;(max-width: 400px) 100vw, 400px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What does it take to add such a button to the browser? It turns out to be surprisingly easy. In Firefox, this requires about 15 lines of code. In Chrome, it&apos;s even less. Opera just works by repackaging the Chrome extension.&lt;/p&gt;
&lt;p&gt;So, because the web we want is not things running in just a single browser we made extensions for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/start-a-videochat-on-talk/achmeeanjkbjiinehooninjbabecohhk&quot;&gt;Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://addons.mozilla.org/firefox/addon/talkyio-webrtc-videochat/&quot;&gt;Firefox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://addons.opera.com/extensions/details/start-a-videochat-on-talkyio/&quot;&gt;Opera&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/27e91d11916f8697dfdf9b9c73e22e52/a0209/hello-talky.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 13.245033112582782%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAnUlEQVQI11WOywqDMBBF/f9P66YPjNCFUNRoGqpJTGKiC2+dEQpdHGa4MOdO8RofGL3bgw+w1kBKiWmaMM8zjDFwzmFZFibGyKQtY13XP3LOSCmhUFrunezwVoplTdOyhIQ0KdNaYxgGGGs5ay9P3K83iKpCWZYQQqA69rquUQQf6XgnAeG9/31CnPKzIITAfJqzvO97nup4hgqp+Aul7uHoL2j79QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Talky Button in Firefox alongside Hello&quot;
        title=&quot;&quot;
        src=&quot;/static/27e91d11916f8697dfdf9b9c73e22e52/90cbd/hello-talky.png&quot;
        srcset=&quot;/static/27e91d11916f8697dfdf9b9c73e22e52/29fe9/hello-talky.png 151w,
/static/27e91d11916f8697dfdf9b9c73e22e52/6728c/hello-talky.png 303w,
/static/27e91d11916f8697dfdf9b9c73e22e52/90cbd/hello-talky.png 605w,
/static/27e91d11916f8697dfdf9b9c73e22e52/a0209/hello-talky.png 725w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Each of these extensions adds a small button to your browser UI. Click on that button and a new tab will open that sends you to room on Talky. No need to think of a room name, we&apos;re generating a nice and memorable phrase for you!&lt;/p&gt;
&lt;p&gt;On the more critical side, Mozila is making a communications choice for their users with Hello. &lt;/p&gt;
&lt;p&gt;Hello is not based on an &lt;a href=&quot;http://xmpp.org/2015/01/its-all-about-choices-and-control/&quot;&gt;open standard&lt;/a&gt;. Now, the current version of Talky isn&apos;t either, but you can download both the client and serverside code that powers the current version. (The forthcoming version of Talky is entirely based on open standards, and all of the libraries we&apos;ve &lt;a href=&quot;http://github.com/otalk&quot;&gt;open sourced here&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;To take up the question posed by palava.tv: &lt;strong&gt;Mozilla, why don&apos;t you allow user choice with the &quot;hello&quot; button?&lt;/strong&gt; Do we have to ask the &lt;a href=&quot;http://en.wikipedia.org/wiki/BrowserChoice.eu&quot;&gt;European Commission&lt;/a&gt; for an opinion?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Chrome update killed the WebRTC star]]></title><description><![CDATA[&yet is a highly distributed team, with yetis all over North America and Europe. To keep in touch, we use Talky on a daily basis for…]]></description><link>https://blog.andyet.com/2015/01/30/chrome-update-killed-the-webrtc-star/</link><guid isPermaLink="false">https://blog.andyet.com/2015/01/30/chrome-update-killed-the-webrtc-star/</guid><pubDate>Fri, 30 Jan 2015 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;#x26;yet is a highly distributed team, with yetis all over North America and Europe. To keep in touch, we use &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; on a daily basis for impromptu discussions among our teammates. Unfortunately, Talky doesn&apos;t quite work for our all-hands meetings because &quot;full-mesh&quot; media sharing only functions well when the number of people in the conference is small. To change that, we are working on an improved version that we&apos;ve tested up to 20 people, internally known as &lt;a href=&quot;http://blog.andyet.com/2014/10/22/Talky-2-is-Coming&quot;&gt;Talky 2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Last Friday we had another weekly update meeting and Talky 2 would not work - all the videos remained black. Switching from Chrome to Opera resolved the problem for a while, but at some point every participant in the conference had their browser crash. We had to switch back to Hangouts. Which was embarrassing.&lt;/p&gt;
&lt;h2 id=&quot;what-happened&quot;&gt;&lt;a href=&quot;#what-happened&quot; aria-label=&quot;what happened permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What happened?&lt;/h2&gt;
&lt;p&gt;Crashing every browser (including Opera) was something I had been expecting. We had seen it before and currently it is being investigated by the WebRTC team. It is quite a serious issue and getting them more data to investigate what is going on helps. Showing black videos, on the other hand, was a behavior I had not seen before, so I went to investigate. I could not reproduce this behavior on my Linux laptop and It seemed to happen only on the Macintosh computer we use in our meeting room.&lt;/p&gt;
&lt;p&gt;The first thing I noticed was that it was running Chrome 41. Chrome 41 is not the version I was testing with and is currently in beta stage. The way Google rolls out updates means that a small percentage of users get those updates even on the stable channel, so if there are any major problems they might be noticed at that point and can still be fixed before affecting the majority of users.&lt;/p&gt;
&lt;p&gt;So... when i&apos;m debugging a WebRTC problem, the first thing I do is to check the &lt;a href=&quot;chrome://webrtc-internals&quot;&gt;chrome://webrtc-internals&lt;/a&gt; page which shows all the API calls and statistics information. If something breaks, there is quite a good chance that you can see what might be wrong on that page.&lt;/p&gt;
&lt;h2 id=&quot;was-it-talky-or-jitsi-videobridge-or-something-else&quot;&gt;&lt;a href=&quot;#was-it-talky-or-jitsi-videobridge-or-something-else&quot; aria-label=&quot;was it talky or jitsi videobridge or something else permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Was it Talky or Jitsi Videobridge? Or something else?&lt;/h2&gt;
&lt;p&gt;Indeed the page showed that Chrome had failed to establish a connection to the &lt;a href=&quot;https://jitsi.org/Projects/JitsiVideobridge&quot;&gt;Jitsi Videobridge&lt;/a&gt; (which is the thing allowing user to scale to a much higher number of participants than the current Talky). It was apparent that Chrome only sent a few bytes and then stopped, even though the basic connection seemed to be up. This looked like, despite being able to establish a basic ICE connection, it failed to set-up the DTLS encryption. To find and verify this hunch I dumped the low-level traffic using Wireshark, which showed a DTLS Alert packet it described as &lt;code class=&quot;language-text&quot;&gt;Level: Fatal, Description: Illegal Parameter&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Sounds scary, eh?&lt;/p&gt;
&lt;p&gt;At this point I started to wonder if this was something related to just Talky or would this also affect other applications like &lt;a href=&quot;https://meet.jit.si/&quot;&gt;Jitsi Meet&lt;/a&gt;? Turns out it did affect them, so I pinged the Jitsi team and got a response very quickly – they had started to notice this a few hours earlier as well.&lt;/p&gt;
&lt;p&gt;So a Chrome update was about to break both our WebRTC applications... I have been afraid of that happening ever since starting to work on WebRTC about two and a half years ago. I&apos;ve had my share of WebRTC-related crashes, crashing almost every release since Chrome 29, but those had never affected all users. &lt;/p&gt;
&lt;p&gt;The Chrome 41 &lt;a href=&quot;https://groups.google.com/forum/#!topic/discuss-webrtc/aGsdjGtjIQA&quot;&gt;WebRTC release notes had been published&lt;/a&gt; earlier last week. I tend to review them very carefully and they did not contain any hints on changes related to DTLS.  George Politis from the Jitsi team filed an &lt;a href=&quot;https://code.google.com/p/webrtc/issues/detail?id=4223&quot;&gt;issue&lt;/a&gt; in the WebRTC bug tracker and I immediately poked Vikas Marwaha, the awesome Google engineer who writes the release notes and triages all reported issues. He was able to reproduce it and assigned it to the person responsible for that area within less than 25 minutes.&lt;/p&gt;
&lt;p&gt;That&apos;s quite a good response time, especially considering it was 3pm on a Friday. The issue got reassigned to the BoringSSL team the same day still and was fixed on Monday morning. The fix will be included in the release version of Chrome 41.&lt;/p&gt;
&lt;p&gt;By a whisker we caught it early in the Chrome Beta phase.&lt;/p&gt;
&lt;h2 id=&quot;why-did-we-not-notice-this-earlier&quot;&gt;&lt;a href=&quot;#why-did-we-not-notice-this-earlier&quot; aria-label=&quot;why did we not notice this earlier permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why did we not notice this earlier?&lt;/h2&gt;
&lt;p&gt;We do some &lt;a href=&quot;https://blog.andyet.com/2014/09/29/testing-webrtc-applications&quot;&gt;automated testing&lt;/a&gt; that should have caught this. However, since we run the testing tool on Linux servers and Linux was not affected our own testing process did not catch the change when it was introduced. Since it only happens with the Jitsi Videobridge and the BouncyCastle TLS library used by it, the &lt;a href=&quot;http://googletesting.blogspot.se/2014/08/chrome-firefox-webrtc-interop-test-pt-1.html&quot;&gt;Chrome-Firefox interop testing&lt;/a&gt; that Google does didn&apos;t show the problem either.&lt;/p&gt;
&lt;p&gt;From the Google side, while I do not want to experience such a situation again, the way this was handled makes me confident that they take such issues very seriously. The WebRTC team seems to have been surprised by the change in BoringSSL as well. &lt;/p&gt;
&lt;p&gt;Effectively &quot;what if a Chrome upgrade kills your WebRTC applications&quot; is FUD. The Chrome release process makes it possible to detect such changes relatively early, so if as a developer you are not working in the &lt;a href=&quot;https://www.google.com/chrome/browser/canary.html&quot;&gt;Canary version&lt;/a&gt; you should start doing that today. And get automated testing done. On all platforms. Oh, and also across other browsers like Firefox and Opera, just to increase the size of the testing matrix.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Jaime Robles at Enterprise Week]]></title><description><![CDATA[Recently, several members of our team participated in a week-long business simulation called Enterprise Week for a local school district. It…]]></description><link>https://blog.andyet.com/2015/01/27/jaime-at-enterprise/</link><guid isPermaLink="false">https://blog.andyet.com/2015/01/27/jaime-at-enterprise/</guid><pubDate>Tue, 27 Jan 2015 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently, several members of our team participated in a week-long business simulation called Enterprise Week for a local school district. It was featured in an earlier post &lt;a href=&quot;https://blog.andyet.com/2014/12/12/what-eric-learned&quot;&gt;here&lt;/a&gt; and was also described in one of the &lt;a href=&quot;http://createsend.com/t/r-0BB20BB514E6368F2540EF23F30FEDED&quot;&gt;December&lt;/a&gt; dispatches for our online community &lt;a href=&quot;http://andyet.com/andyou&quot;&gt;&amp;#x26;you&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;The week culminated with a touching and personal closing talk by former Enterprise Week participant, illustrator and yeti, &lt;a href=&quot;http://andyet.com/team/jaime&quot;&gt;Jaime Robles&lt;/a&gt;. We are very proud to now be able to present Jaime&apos;s talk to you. &lt;/p&gt;
&lt;iframe src=&quot;//player.vimeo.com/video/117189558&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt; &lt;p&gt;&lt;a href=&quot;http://vimeo.com/117189558&quot;&gt;Jaime Robles 2014 Pasco School District&amp;#039;s Enterprise Program&lt;/a&gt; from &lt;a href=&quot;http://vimeo.com/andyet&quot;&gt;&amp;amp;yet&lt;/a&gt; on &lt;a href=&quot;https://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Native Web Apps]]></title><description><![CDATA[The web platform has evolved. Browsers are no longer just document renderers, they have become the most capable and ubiquitous application…]]></description><link>https://blog.andyet.com/2015/01/22/native-web-apps/</link><guid isPermaLink="false">https://blog.andyet.com/2015/01/22/native-web-apps/</guid><pubDate>Thu, 22 Jan 2015 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The web platform has evolved. Browsers are no longer just document renderers, they have become the most capable and ubiquitous application runtimes on the planet. &lt;/p&gt;
&lt;p&gt;Right now, the most common term for applications that use the browser as a runtime is &quot;Single Page App&quot;. I’ve even heard people pronounce it like the word &quot;spa&quot;. If you’ve done this, we can probably still be friends :)&lt;/p&gt;
&lt;p&gt;Personally, I’ve always disliked the term &quot;single page app&quot; because it fails to describe what my applications are. The fact that the app consists of a single initial HTML page is not what makes it interesting or unique. In fact, often times it’s plain wrong. A well-built &quot;single page app&quot; updates the URL as the user navigates around to different &quot;pages&quot; within the app, keeping their place if they refresh or share that URL. Perhaps at one time the &quot;single pageness&quot; was its defining characteristic, but these days the term makes it sound more like you’re building an application that doesn’t respect the URL and thus breaks the web.&lt;/p&gt;
&lt;p&gt;When I was first writing &lt;a href=&quot;http://humanjavascript.com/&quot;&gt;Human JavaScript&lt;/a&gt; I struggled to find a good word for these apps that I could use throughout the book. Each of them has issues, here are a few in particular:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Browser app&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I nearly picked this one. It’s good, but it fails to cover hybrid and other apps that run in a web-like runtime that isn’t a browser. As I’ve written previously, I believe &lt;a href=&quot;http://blog.andyet.com/2014/01/17/web-has-outgrown-the-browser&quot;&gt;the web has outgrown the browser&lt;/a&gt; and also, it can possibly be confused with creating something like &lt;a href=&quot;https://developer.chrome.com/apps/about_apps&quot;&gt;a chrome app&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clientside app / clientside web app&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is pretty good too, but also falls short. The name implies that there’s also a server-side component and doesn’t make any distinction about what type of client it is. Inserting &quot;web&quot; in the middle helps that, but it still somehow fails to capture what it is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JavaScript App&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;Node.js exists, need I say more? There are plenty of javascript apps that do everything else under the sun, like &lt;a href=&quot;http://nodebots.io/&quot;&gt;control robots&lt;/a&gt; for example. This simply isn’t specific enough.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTML5 app&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not bad, but again, to many of us anything that has &quot;HTML&quot; in it, is strongly associated with static markup, when clearly the thing that makes the apps we’re discussing unique is their dependence on the web runtime. &lt;/p&gt;
&lt;h2 id=&quot;what-is-their-defining-feature&quot;&gt;&lt;a href=&quot;#what-is-their-defining-feature&quot; aria-label=&quot;what is their defining feature permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is their defining feature?&lt;/h2&gt;
&lt;p&gt;The thing these apps &lt;em&gt;all&lt;/em&gt; have in common is that they all depend on the native web technologies: HTML, CSS, and JavaScript (arguably, you could add WebGL to that list). &lt;/p&gt;
&lt;p&gt;In the modern web these are not enhancements, they &lt;em&gt;are&lt;/em&gt; the native technologies.&lt;/p&gt;
&lt;p&gt;Therefore I think it’s time we start calling them what they actually are: &lt;strong&gt;Native Web Apps&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;why-native-web-app&quot;&gt;&lt;a href=&quot;#why-native-web-app&quot; aria-label=&quot;why native web app permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why &quot;Native Web App&quot;?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The exact capabilities of each of the individual web technologies is not what matters. This term works whether your markup is HTML 4.01, HTML5 or HTML37. It doesn’t matter, and the term won’t be obsoleted by the next version of any spec.&lt;/li&gt;
&lt;li&gt;It covers the case where the runtime is a regular browser, a webview, an OS such as Firefox OS or Chrome OS, or something like &lt;a href=&quot;https://www.google.com/webhp?sourceid=chrome-instant&amp;#x26;ion=1&amp;#x26;espv=2&amp;#x26;ie=UTF-8#q=node-webkit&quot;&gt;node-webkit&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;The key point is that it’s written for the technologies that are native to the web platform.&lt;/li&gt;
&lt;li&gt;The term makes a clear distinction from the serverside. &lt;/li&gt;
&lt;li&gt;It even works OK as an acronym if you’re into that sort of thing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I didn’t coin the term, it was suggested by &lt;a href=&quot;https://twitter.com/adambrault&quot;&gt;Adam Brault&lt;/a&gt; when I was complaining to him about this naming problem while, ironically enough, preparing for the talk I gave at &lt;a href=&quot;http://ffconf.org/&quot;&gt;FFConf&lt;/a&gt; called &quot;A Single Page Story&quot; in which I also discuss progressive enhancement, isomorphic apps, Twitter’s famous switch back to server-rendered apps, etc. That talk is here, if you’re curious:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/hrAssE8meRo&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;Adam and I work together at &lt;a href=&quot;http://andyet.com/&quot;&gt;&amp;#x26;yet&lt;/a&gt; where we’ve been helping teams build Native Web Apps since before &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt; was a thing.&lt;/p&gt;
&lt;p&gt;Anyway, the gist of that talk is that the web runtime has evolved into quite an impressive list of capabilities and with the addition of full offline support that &lt;a href=&quot;http://www.html5rocks.com/en/tutorials/service-worker/introduction/&quot;&gt;Service Worker&lt;/a&gt; will bring, it becomes an incredible and very complete platform to build for. Just look at what it offers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTML5, CSS3: for performant UI rendering (optimized for GPU control)&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Networking capabilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;XMLHttpRequest: our HTTP client&lt;/li&gt;
&lt;li&gt;WebSocket: for fast, bi-directional connections to servers&lt;/li&gt;
&lt;li&gt;PeerConnection: for peer to peer netwoking&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;WebAudio: for impressive audio creation and manipulation&lt;/li&gt;
&lt;li&gt;Data storage: indexDB, localStorage, sessionStorage&lt;/li&gt;
&lt;li&gt;WebGL/Canvas: for advanced rendering capabilities&lt;/li&gt;
&lt;li&gt;getUserMedia: for access to user microphone and video cameras&lt;/li&gt;
&lt;li&gt;Web Workers: for parallel processing&lt;/li&gt;
&lt;li&gt;Caching and Offline Support: via cache headers and app cache&lt;/li&gt;
&lt;li&gt;Geolocation&lt;/li&gt;
&lt;li&gt;Notification API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Coming soon:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.html5rocks.com/en/tutorials/service-worker/introduction/&quot;&gt;Service Worker&lt;/a&gt;: a programmable cache that can intercept and choose what to do with network requests. In other words, incredibly precise control of offline behavior. It just landed in Chrome stable yesterday and &lt;a href=&quot;https://jakearchibald.github.io/isserviceworkerready/&quot;&gt;is in progress&lt;/a&gt; in FF.&lt;/li&gt;
&lt;li&gt;Background processing and push notifications (also via Service Worker).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.google.com/search?q=json+app+manifest&amp;#x26;oq=json+app+manifest&amp;#x26;aqs=chrome..69i57j69i60l5.2518j0j1&amp;#x26;sourceid=chrome&amp;#x26;es_sm=119&amp;#x26;ie=UTF-8&quot;&gt;Standardized JSON App manifests&lt;/a&gt; for describing installable web apps.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web-payments.org/&quot;&gt;Web Payments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other benefits include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dynamic loading of external libraries&lt;/li&gt;
&lt;li&gt;Zero configuration installs&lt;/li&gt;
&lt;li&gt;Expressive, extensible, event-driven native language&lt;/li&gt;
&lt;li&gt;These runtimes are already installed on billions of devices&lt;/li&gt;
&lt;li&gt;Can be &quot;wrapped&quot; into &quot;native-feeling&quot; apps on a wide variety of platforms&lt;/li&gt;
&lt;li&gt;It’s easily the most open and accessible platform on the planet. We don’t have to pay homage at the &quot;walled gardens&quot; of the world, like the Apple App Store.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’d argue it’s the most desirable and complete platform on the planet and I’m convinced we’re just at the beginning of a long growth curve of these types of apps. If you’re convinced otherwise or have other thoughts &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;let me know on Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Join us! Let’s build amazing Native Web Apps and call them what they actually are.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[On writing maintainable front-end systems]]></title><description><![CDATA[I've been always drawn to bringing structure where it was lacking,  systematizing information and defining processes. Not sure if that's a…]]></description><link>https://blog.andyet.com/2015/01/21/on-maintainable-front-end-systems/</link><guid isPermaLink="false">https://blog.andyet.com/2015/01/21/on-maintainable-front-end-systems/</guid><pubDate>Wed, 21 Jan 2015 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve been always drawn to bringing structure where it was lacking,  systematizing information and defining processes. Not sure if that&apos;s a designer&apos;s trait (along with a particular fondness of symmetry) but it continues to carry through all the work I do. One of the ways I utilise it is by creating standardized approaches for others to follow.&lt;/p&gt;
&lt;h2 id=&quot;best-practices&quot;&gt;&lt;a href=&quot;#best-practices&quot; aria-label=&quot;best practices permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Best practices&quot;&lt;/h2&gt;
&lt;p&gt;When writing software we often look for guidelines on how to do it in the most effective and standards-compliant way. We search for patterns we can follow. Standards are obvious signposts leading us to valid code (which is why we call them standards in the first place). The other way of approaching this problem is to look for so-called best practices.&lt;/p&gt;
&lt;p&gt;Why “so-called”? Because we don’t really know where these rules came from. Is it because of the broad adoption within a given community, or something else?&lt;/p&gt;
&lt;p&gt;The tricky thing about so-called &quot;best practices&quot; is that they have been widespread, oftentimes leading to &lt;a href=&quot;http://www.urbandictionary.com/define.php?term=Cargo-Culting&quot;&gt;cargo culting&lt;/a&gt; and detaching the standard from the &quot;why&quot; behind it.&lt;/p&gt;
&lt;p&gt;While an approach may be valid for one person, one group or one section of the industry, it might be completely disempowering and useless for others.&lt;/p&gt;
&lt;p&gt;A good example of this is web sites vs. web apps: there are a different set of practices that should be applied to each.&lt;/p&gt;
&lt;p&gt;Like baking recipes, one approach might result in the most visually appealing pie, but that doesn’t necessarily mean everyone will enjoy eating it.&lt;/p&gt;
&lt;h2 id=&quot;the-human-side-of-technology&quot;&gt;&lt;a href=&quot;#the-human-side-of-technology&quot; aria-label=&quot;the human side of technology permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The human side of technology&lt;/h2&gt;
&lt;p&gt;Practices are often built without targeting the crucial aspect of collaboration—the human factor.&lt;/p&gt;
&lt;p&gt;The secret lies in understanding of good patterns and mindfully applying them (and we’ve elaborated on that a little bit &lt;a href=&quot;https://blog.andyet.com/2015/01/15/find-your-own-best-practices-for-node-with-node-consulting&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;A starting point for building up effective collaboration is to create resources than can serve as learning and reference materials. One of the ways to do so is to have a style guide (see &lt;a href=&quot;https://github.com/styleguide&quot;&gt;Github&lt;/a&gt;, &lt;a href=&quot;http://ux.mailchimp.com/patterns/&quot;&gt;MailChimp&lt;/a&gt;, &lt;a href=&quot;http://pasteup.guim.co.uk/index.html&quot;&gt;The Guardian&lt;/a&gt; and &lt;a href=&quot;http://alistapart.com/about/style-guide&quot;&gt;A List Apart&lt;/a&gt;). They feature not only coding patterns but also specific interface elements. They are becoming more and more widely adopted—not only by big companies or teams. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Collaboration truly starts with just one person&lt;/strong&gt;—projects are handed off, contributors appear, people change jobs. &lt;/p&gt;
&lt;p&gt;Writing software as if we are the only person that ever has to comprehend it is one of the biggest mistakes and false assumptions that can be made. The &lt;strong&gt;greatest challenge that we’re facing with software isn’t technology itself&lt;/strong&gt;, but effective collaboration.&lt;/p&gt;
&lt;h2 id=&quot;what-if-you-dont-agree&quot;&gt;&lt;a href=&quot;#what-if-you-dont-agree&quot; aria-label=&quot;what if you dont agree permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What if you don&apos;t agree?&lt;/h2&gt;
&lt;p&gt;You&apos;re likely to have instant agreement on some standards within your team, but guaranteed there will be far less easy consensus on others.&lt;/p&gt;
&lt;p&gt;In a recent discussion about standardizing our approaches, it became apparent that on some stylistic choices I disagreed with my teammates. For example, with &lt;a href=&quot;http://jade-lang.com&quot;&gt;Jade&lt;/a&gt;, I prefer including classes alongside other html attributes like so:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;p(class=&amp;quot;some-special-paragraph another-exciting-class&amp;quot;) Here&amp;#39;s our amazing content.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But many of my other teammates preferred to use Jade&apos;s dot-chain approach, which creates a visual separation from other attributes:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;p.some-special-paragraph.another-exciting class Here&amp;#39;s our amazing content.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I was the one trusted by the team to make the final call on our standardization decisions. So what did I do?&lt;/p&gt;
&lt;p&gt;I didn&apos;t have a strong argument why one approach was better or worse, so I chose the approach preferred by more people.&lt;/p&gt;
&lt;p&gt;You&apos;re going to have disagreement on what conventions are right for your team and that&apos;s to be expected. But as Lynn talks about in &lt;a href=&quot;https://blog.andyet.com/2014/11/21/on-making-design-decisions&quot;&gt;this post about making design decisions&lt;/a&gt;, the important thing is to &quot;decide to decide.&quot; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It doesn&apos;t really matter &lt;em&gt;what&lt;/em&gt; you choose, as long as you all agree to abide by one approach.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;building-empowering-resources&quot;&gt;&lt;a href=&quot;#building-empowering-resources&quot; aria-label=&quot;building empowering resources permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Building empowering resources&lt;/h2&gt;
&lt;p&gt;As &amp;#x26;yet has grown, we too have noticed an emerging need for resources that will not only bring cohesiveness to our work but also empower less front-end savvy members of the team to improve.&lt;/p&gt;
&lt;p&gt;I’ve worked for several months on various projects surrounding this effort, the beginning of it being the &lt;a href=&quot;http://yetiguide.com/&quot;&gt;Yeti Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yeti Guide is a collection of general rules for writing maintainable front-end systems in Stylus and Jade. &lt;/p&gt;
&lt;p&gt;Naturally, it is opinionated and includes some of our preferential choices, but it’s also inspired by the work of some of the most respected front-end developers we know—&lt;a href=&quot;https://twitter.com/mdo&quot;&gt;Mark Otto&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/necolas&quot;&gt;Nicolas Gallagher&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/csswizardry&quot;&gt;Harry Roberts&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Hopefully it can serve as a source of inspiration to some of you.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We&apos;d love to help you find your team&apos;s best practices for frontend development. A great starting point could be a &lt;strong&gt;frontend code audit by our super-friendly team of veterans.&lt;/strong&gt; &lt;a href=&quot;http://andyet.com/contact&quot;&gt;Reach out to our team&lt;/a&gt; and say &lt;a href=&quot;http://twitter.com/fox&quot;&gt;@fox&lt;/a&gt; sent you. :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Find your own best practices for Node with Node Consulting from &yet]]></title><description><![CDATA[Node.js doesn't have the same problems as the platforms that you're used to—it has entirely new problems!The landscape is so different, and…]]></description><link>https://blog.andyet.com/2015/01/15/find-your-own-best-practices-for-node-with-node-consulting/</link><guid isPermaLink="false">https://blog.andyet.com/2015/01/15/find-your-own-best-practices-for-node-with-node-consulting/</guid><pubDate>Thu, 15 Jan 2015 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Node.js doesn&apos;t have the same problems as the platforms that you&apos;re used to—it has entirely new problems!&lt;/p&gt;
&lt;p&gt;The landscape is so different, and there are so many libraries, packages, and approaches that it is tough to navigate. There are just too many opinions on the &quot;best approach.&quot; Even the &lt;a href=&quot;https://iojs.org&quot;&gt;io.js fork of Node&lt;/a&gt; (which we&apos;re excited about and hope gets upstreamed to Node soon) is a good example of this unique ecosystem.&lt;/p&gt;
&lt;p&gt;Ask 12 Node.js developers which is the best ORM to use, or how structure your HTTP handlers, and you&apos;ll get 15 answers. On these and hundreds of other topics, there is no consensus, and there are numerous approaches and philosophies to choose from. Many a developer has followed their instincts and gut feelings, only to make a mess.&lt;/p&gt;
&lt;p&gt;This might be the complete opposite problem that you&apos;re used to. Maybe you came from Django, like &amp;#x26;yet did, and were looking for something less focused on content-driven applications and sites. Maybe you came from Rails, like many of us, and were frustrated by the amount of convention, being railroaded down a single path. Maybe you&apos;re making a transition from Java or PHP.&lt;/p&gt;
&lt;p&gt;Whatever background you and your team are coming from, it&apos;s almost certain the &quot;best practices&quot; landscape is much simpler than Node&apos;s.&lt;/p&gt;
&lt;p&gt;Rather than subscribing to an opinionated set of &quot;best practices,&quot; find some &lt;em&gt;good&lt;/em&gt; practices, and understand where and how to apply them. There is no one-size-fits-all solution in Node.js because the problems we aim to solve are subtle and varied. We &lt;em&gt;want&lt;/em&gt; flexibility. In order to find the best practices for your problem space, you need understanding.&lt;/p&gt;
&lt;h1 id=&quot;good-practices--understanding--your-best-practices&quot;&gt;&lt;a href=&quot;#good-practices--understanding--your-best-practices&quot; aria-label=&quot;good practices  understanding  your best practices permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Good Practices + Understanding = Your Best Practices&lt;/h1&gt;
&lt;p&gt;The great part is: you probably already have a pretty good understanding of your problem. One way of thinking about programming is: understanding a problem so completely that you can express it in software. The gap in your understanding then, is in where and how to apply the varied good practices.&lt;/p&gt;
&lt;p&gt;Here at the &amp;#x26;yet, we&apos;ve gone through the expatriate pain that a lot of people are currently in.&lt;/p&gt;
&lt;p&gt;We&apos;ve been shipping large-scale Node.js applications since 2010, but originally, &amp;#x26;yet wrote Django applications. We enjoyed Django, but for the types of applications we were writing, we found it too focused on needs that were merely tangentially related to the problems we were trying to solve. We experimented with early builds of Node.js and soon found ourselves preferring the freedom to find our own best practices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We&apos;d like to help you find that freedom (and power) too, by giving you confidence through knowledge and understanding.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But the nature of Node makes doing this very difficult and time consuming. &lt;/p&gt;
&lt;p&gt;We hear it often: &quot;Can&apos;t someone just tell me &lt;em&gt;the&lt;/em&gt; way to do this?&quot; We find the lack of One True Way™ to be one of Node&apos;s greatest strengths, but this is undoubtedly frustrating.&lt;/p&gt;
&lt;h1 id=&quot;people-turn-information-into-knowledge-and-understanding-in-a-complex-landscape-there-is-simply-no-substitution-for-experience&quot;&gt;&lt;a href=&quot;#people-turn-information-into-knowledge-and-understanding-in-a-complex-landscape-there-is-simply-no-substitution-for-experience&quot; aria-label=&quot;people turn information into knowledge and understanding in a complex landscape there is simply no substitution for experience permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;em&gt;People&lt;/em&gt; turn information into knowledge and understanding. In a complex landscape, there is simply no substitution for experience.&lt;/h1&gt;
&lt;p&gt;When it comes to Node, &lt;strong&gt;there are very few teams who have &amp;#x26;yet&apos;s depth of experience.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We’ve been heavy users of Node.js since its earliest days and it has remained our go-to tool for building a broad range of applications since then. During that time we’ve helped enterprises such as AT&amp;#x26;T, Netflix, CAA (the world’s largest talent agency), Walmart, Major League Soccer, Pacific Northwest National Labs, and many others.&lt;/p&gt;
&lt;p&gt;A few more fun facts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our security team, &lt;a href=&quot;https://liftsecurity.io/&quot;&gt;^Lift&lt;/a&gt;, created the &lt;a href=&quot;https://nodesecurity.io/&quot;&gt;Node Security Project&lt;/a&gt; to audit security of npm modules, provide advisories of known vulnerabilities, and provide easy access to the data back to the community.&lt;/li&gt;
&lt;li&gt;Our team has several core contributors to &lt;a href=&quot;http://hapijs.com/&quot;&gt;Hapi.js&lt;/a&gt;, the most battle-tested node.js HTTP framework, easily handling web traffic for Walmart during their busiest shopping times of the year for two years in a row.&lt;/li&gt;
&lt;li&gt;Our developers have contributed hundreds of open source packages to &lt;a href=&quot;http://npmjs.org/&quot;&gt;npm repository&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We are enterprise-grade node.js veterans:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our security team is trusted by GitHub, npm inc., AT&amp;#x26;T, Digital Ocean and many more.&lt;/li&gt;
&lt;li&gt;We use proven node.js powered architectures&lt;/li&gt;
&lt;li&gt;We have an experienced node.js operations and deployment team&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;We were using CommonJS modules and npm for client-side code before this approach was made popular by &lt;a href=&quot;http://browserify.org/&quot;&gt;Browserify&lt;/a&gt; (which we love!)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;we-can-help-you-build-a-road-map-for-succeeding-with-nodefrom-wherever-youre-at-to-wherever-youre-going&quot;&gt;&lt;a href=&quot;#we-can-help-you-build-a-road-map-for-succeeding-with-nodefrom-wherever-youre-at-to-wherever-youre-going&quot; aria-label=&quot;we can help you build a road map for succeeding with nodefrom wherever youre at to wherever youre going permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;We can help you build a road map for succeeding with Node—from wherever you&apos;re at to wherever you&apos;re going.&lt;/h1&gt;
&lt;p&gt;Let&apos;s get together and explore your pain points, the problem space of your software, and what Node approaches make for a good fit there.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We&apos;ll help you with your architecture by creating data-workflows, API documents, database structures, code skeletons and examples, demo applications, and document a clear path to where you&apos;re going.&lt;/li&gt;
&lt;li&gt;We can do code reviews for what you have now, which not only tells you where to improve, but how to get there. &lt;/li&gt;
&lt;li&gt;We offer training for your developers, and can lend you our time to help you get your work done.&lt;/li&gt;
&lt;li&gt;We can even help you to plan for your scaling needs and provide advice and tools for deployment and operations.&lt;/li&gt;
&lt;li&gt;And as you build, we can provide on-call support for your developers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our team of veteran Node developers can help you fill in your gaps with the knowledge of good practices and the understanding (the why&apos;s and whens) to choose your own best practices. Ultimately, we&apos;ll enable you to succeed, and give you the confidence to keep succeeding. We can help you get to your destination by the route that serves you best. If you need it, we can even provide some extra hands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ready to talk? We&apos;d love to chat about how we can help you use Node to get where you&apos;re going with confidence. &lt;a href=&quot;http://andyet.com/contact&quot;&gt;Let&apos;s talk!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Tao of Ops: TURN for WebRTC]]></title><description><![CDATA[When launching our Talky videochat service almost two years ago there was one thing missing: the TURN server.WebRTC creates peer-to-peer…]]></description><link>https://blog.andyet.com/2015/01/14/turn-for-webrtc/</link><guid isPermaLink="false">https://blog.andyet.com/2015/01/14/turn-for-webrtc/</guid><pubDate>Wed, 14 Jan 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When launching our &lt;a href=&quot;http://talky.io&quot;&gt;Talky&lt;/a&gt; videochat service &lt;a href=&quot;https://blog.andyet.com/2013/02/22/introducing-simplewebrtcjs-and-conversatio&quot;&gt;almost two years ago&lt;/a&gt; there was one thing missing: the TURN server.&lt;/p&gt;
&lt;p&gt;WebRTC creates peer-to-peer connections between browsers to transfer the audio and video data, but sometimes it needs a little help to establish a connection. The TURN server is the thing that helps here: it is deployed on the Internet and relays data for two clients that fail to establish a direct, P2P connection (thus avoiding the dreaded &quot;black video&quot; problem). TURN is generally considered one of the &lt;a href=&quot;http://www.chriskranky.com/webrtc-turn-restricted-network/&quot;&gt;hard topics&lt;/a&gt; when people start doing WebRTC and crucial to running a successful service.&lt;/p&gt;
&lt;p&gt;When I started at &amp;#x26;yet back in March one of the first things I did was to add a TURN server. We choose the open-source &lt;a href=&quot;http://creytiv.com/restund.html&quot;&gt;restund&lt;/a&gt; server because it had proven to be mature and very easy to &lt;a href=&quot;https://code.google.com/p/webrtc/issues/detail?id=1197&quot;&gt;extend&lt;/a&gt; earlier. The &lt;a href=&quot;https://code.google.com/p/rfc5766-turn-server/&quot;&gt;rfc-5766-turn-server&lt;/a&gt; is another popular choice here, but the design and extensibility of restund was more appealing to us.&lt;/p&gt;
&lt;p&gt;In response to adding a TURN server, the number of &quot;black video&quot; problems that users reported went down to almost zero. The exception were Firefox users and this turned out to be a &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1000858&quot;&gt;Firefox bug&lt;/a&gt; which was fixed.&lt;/p&gt;
&lt;p&gt;This worked for a while, but as Talky.io usage grew, we had an outage.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/turn-onfire.png&quot; alt=&quot;Open TURN connections&quot;&gt;&lt;/p&gt;
&lt;p&gt;This was very noticeable in our metrics, but on the Operations side it was not noticed early enough. It turned out we had a too-hard limit on the maximum number of concurrent allocations and &lt;a href=&quot;https://code.google.com/p/chromium/issues/detail?id=406578&quot;&gt;Chrome was keeping allocations around longer than required&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that our TURN server was moving from a research role to a production role we started looking very extensively into the operational aspects of running TURN servers. It is not as simple as &quot;install it and you&apos;re done&quot; so we would need to build or find monitoring and server management tools for restund.&lt;/p&gt;
&lt;p&gt;Since you can only fix things that you can measure, we wrote a &lt;a href=&quot;https://github.com/otalk/restund/tree/master/modules/influxdb&quot;&gt;module&lt;/a&gt; that sends the load metrics from restund to &lt;a href=&quot;http://influxdb.com/&quot;&gt;InfluxDB&lt;/a&gt;. We monitor the number of allocations and currently active sessions, the bandwidth, and CPU usage, among other things. We have a nice dashboard which shows the load data, allowing us to figure out if there is a problem with a single look.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/restund-dashboard.png&quot; alt=&quot;TURN metrics dashboard&quot;&gt;&lt;/p&gt;
&lt;p&gt;If we had visualized the data earlier, it would not have taken us long to report the aforementioned bug since the number of allocations is higher than one would expect for the number of clients. &lt;/p&gt;
&lt;p&gt;Our monitoring also enables us to determine that a single instance of restund is very efficient - our instance is able to handle traffic in the order of 100 megabit per second almost exclusive in kernel mode. While this is impressive it does means there is not much room left for optimization, so we quickly needed to be able to scale horizontally in order to meet demand.&lt;/p&gt;
&lt;p&gt;Scaling any network resource requires load balancing - and load balancing means you have to be able to start/stop any service as needed. Initially, adding or removing a TURN server required a restart of the &lt;a href=&quot;https://github.com/andyet/signalmaster&quot;&gt;signalmaster&lt;/a&gt; server which would have caused a disruption of the videochat service. With little effort we can push an updated TURN config to signalmaster which gives us the ability to change the TURN servers on the fly. That way, we can take a TURN server out of service, allowing it to be restarted once all users have switched to other servers. &lt;/p&gt;
&lt;p&gt;Currently, that balancing is a simple random choice but it is trivial to employ a different strategy like figuring in the actual load from the metrics or the geographic location of the client. Together with an automated deployment of TURN servers using &lt;a href=&quot;http://www.ansible.com/home&quot;&gt;Ansible&lt;/a&gt;, we can scale in a matter a minutes.&lt;/p&gt;
&lt;p&gt;Looking back, we&apos;ve realized that this kind of operations infrastructure is one of the most important aspects of running a WebRTC service. &lt;/p&gt;
&lt;p&gt;It&apos;s also the hardest to get right. &lt;/p&gt;
&lt;p&gt;But after almost a year of experimentation, real-world trial and error, measurement and adjustment, we&apos;ve become confident at quickly shaking out the kind of issues that plague those trying to run their own TURN servers.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you&apos;re looking for help configuring your TURN servers, we&apos;d be happy to talk.&lt;/em&gt; &lt;a href=&quot;http://andyet.com/contact&quot;&gt;Feel free to reach out and we&apos;ll get back to you right away&lt;/a&gt;. You can also see more about our WebRTC offerings &lt;a href=&quot;http://andyet.com/webrtc&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;http://andyet.com/talky&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Your real audience]]></title><description><![CDATA[So there you are, scrubbing bugs in your open-source project.  Replying to the people who opened the tickets.  But have you ever thought…]]></description><link>https://blog.andyet.com/2015/01/08/your-real-audience/</link><guid isPermaLink="false">https://blog.andyet.com/2015/01/08/your-real-audience/</guid><pubDate>Thu, 08 Jan 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So there you are, scrubbing bugs in your open-source project.  Replying to the people who opened the tickets.  But have you ever thought about who your actual audience is when you&apos;re interacting with your user base?&lt;/p&gt;
&lt;h2 id=&quot;your-whole-audience&quot;&gt;&lt;a href=&quot;#your-whole-audience&quot; aria-label=&quot;your whole audience permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Your &lt;em&gt;whole&lt;/em&gt; audience&lt;/h2&gt;
&lt;p&gt;Just who are you talking to when you&apos;re interacting with users? When you get right down to it, it&apos;s not just that person, it&apos;s everyone watching. It&apos;s the next person who comes along and reads that ticket. It&apos;s the person way in the future who is deciding whether or not to even use your software.&lt;/p&gt;
&lt;p&gt;Still, it is also that person in that ticket.  A real person who took their valuable time and decided to do all the hard work of finding out how to contact you, compose their thoughts, and reach out to you.&lt;/p&gt;
&lt;h2 id=&quot;doing-the-hard-parts&quot;&gt;&lt;a href=&quot;#doing-the-hard-parts&quot; aria-label=&quot;doing the hard parts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Doing the hard parts&lt;/h2&gt;
&lt;p&gt;As developers, our job is to do the hard parts in order to make it easier on everyone else.  This means that the person you are talking to is &lt;em&gt;your&lt;/em&gt; developer. They&apos;re doing one of the hardest parts for you, often for free.  If that doesn&apos;t deserve the highest respect and response, I don&apos;t know what does.&lt;/p&gt;
&lt;p&gt;The respect you show to that person not only shows them that you value their time, but it sends a message to everyone else who will ever come along and read your responses later.  That ticket is now a part of your project.  &lt;strong&gt;Don&apos;t make the mistake of thinking about your work in terms of the code alone, or even just the code and documentation.&lt;/strong&gt;  The ticketing system for your OSS project is just as much a part of its ecosystem as the code, as the unit tests, as the documentation.  Making them more friendly (and I would argue as a result, more thorough) is always a net positive.&lt;/p&gt;
&lt;h2 id=&quot;be-human&quot;&gt;&lt;a href=&quot;#be-human&quot; aria-label=&quot;be human permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Be human&lt;/h2&gt;
&lt;p&gt;When you are dealing with what can sometimes be a flood of demands for your attention, allow yourself to be human.&lt;/p&gt;
&lt;p&gt;Maybe you&apos;re having a bad day. Maybe the ticket was one too many.  It&apos;s ok.  Let it sit till tomorrow; it&apos;s best to wait and respond correctly than rush in and not.  Also you are totally allowed to apologize.  If you&apos;re suddenly realizing that last week you didn&apos;t handle a ticket in the best way you could, go back right now and make it right.  You can&apos;t change peoples&apos; first impression but you can certainly change their lasting impression.&lt;/p&gt;
&lt;h2 id=&quot;take-a-break&quot;&gt;&lt;a href=&quot;#take-a-break&quot; aria-label=&quot;take a break permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Take a break&lt;/h2&gt;
&lt;p&gt;You can do too much.  Remember, again, it&apos;s always better to take time off than burn out.  The tickets that take more time to fix but are fixed right will last way longer in your community.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There&apos;s no secret behind interacting with your audience. You&apos;re a person! And so are they. Keep that in mind during the process, and the results may surprise you. &lt;/p&gt;
&lt;h2 id=&quot;bonus-round&quot;&gt;&lt;a href=&quot;#bonus-round&quot; aria-label=&quot;bonus round permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bonus round&lt;/h2&gt;
&lt;p&gt;If you&apos;re interested in understanding great open source communities, you may also want to watch &lt;a href=&quot;https://www.youtube.com/watch?v=o3HBe8WhzvE&amp;#x26;index=3&amp;#x26;list=PLXmT1r4krsTqrwW2jjXIXuCtFQ-5BIn-s&quot;&gt;this talk by Hannah Wolfe&lt;/a&gt; from FFConf. She is the CTO of the very popular Ghost blogging platform and has some great insights in her talk.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Modularizing Underscore.js]]></title><description><![CDATA[Underscore.js is the single most depended on module on npm. It's impressive work from Jeremy Ashkenas, who also created Backbone.js and…]]></description><link>https://blog.andyet.com/2015/01/07/modularizing-underscorejs/</link><guid isPermaLink="false">https://blog.andyet.com/2015/01/07/modularizing-underscorejs/</guid><pubDate>Wed, 07 Jan 2015 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://underscorejs.org/&quot;&gt;Underscore.js&lt;/a&gt; is &lt;em&gt;the single most depended on&lt;/em&gt; module on npm. &lt;/p&gt;
&lt;p&gt;It&apos;s impressive work from &lt;a href=&quot;https://twitter.com/jashkenas&quot;&gt;Jeremy Ashkenas&lt;/a&gt;, who also created &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt; and &lt;a href=&quot;http://coffeescript.org/&quot;&gt;CoffeeScript&lt;/a&gt;, all hugely popular projects.  &lt;/p&gt;
&lt;p&gt;But how many of the modules that depend on underscore only use it for one or two methods? I&apos;d venture to guess &lt;em&gt;quite a few&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Conceptually, it makes sense. Why would you go implement your own &lt;code class=&quot;language-text&quot;&gt;debounce&lt;/code&gt; method when &lt;a href=&quot;http://underscorejs.org/#debounce&quot;&gt;there&apos;s one in Underscore&lt;/a&gt; that works great and has clearly been put through its paces. Just install Underscore, be happy, and go fry some bigger fish!&lt;/p&gt;
&lt;p&gt;Also, if you end up with 3 different versions of Underscore installed in an app that&apos;s just going to run using Node.js on a server somewhere, it&apos;s unlikely to cause any problems. &lt;a href=&quot;http://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders&quot;&gt;node&apos;s require mechanism&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt; handles that quite nicely for us.&lt;/p&gt;
&lt;p&gt;But on the clientside, it&apos;s a bit different. We&apos;ve been happily using node and npm to manage code for all our clientside work at &amp;#x26;yet for several years now. Like hipsters, ya know? Before it was cool. But of course for front-end code we have to send all the code we want to use to the browser. In this case, sending 2 or 3 different versions of Underscore plus a few versions of &lt;a href=&quot;https://lodash.com/&quot;&gt;Lo-Dash&lt;/a&gt; might not be what you want. &lt;/p&gt;
&lt;p&gt;Huge deal? Probably not. Annoying? A bit. &lt;/p&gt;
&lt;p&gt;But even if you&apos;re building a whole clientside app where you&apos;re likely to use a good amount of code from it anyway, Underscore is only 5.2kb after all (min+gzip). It&apos;s tolerable, you can probably just include it, try to avoid excess duplication, be happy, and move on.&lt;/p&gt;
&lt;p&gt;But it all starts to feel less awesome when you start writing little clientside &lt;em&gt;libraries&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you&apos;re writing a small re-usable module where you want a performant, cross-browser &lt;code class=&quot;language-text&quot;&gt;each&lt;/code&gt; implementation that works with both objects and arrays, then what? When your whole module is less than 1kb, it may feel a bit odd to tack on a 5kb lib as a dependency.&lt;/p&gt;
&lt;p&gt;SemVer to the rescue, perhaps? (By the way, if you&apos;re not familiar with semver, the first three points on the &lt;a href=&quot;http://semver.org&quot;&gt;SemVer site&lt;/a&gt; will get you a basic understanding.) Couldn&apos;t we just set a flexible version range in our modules so when they&apos;re installed and used they can be de-duped at the project level? &lt;/p&gt;
&lt;p&gt;Well, as it turns out &lt;a href=&quot;https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e&quot;&gt;Jeremy doesn&apos;t like and intentionally doesn&apos;t follow SemVer&lt;/a&gt;. So, since Underscore doesn&apos;t follow SemVer, there can be (and have been) breaking changes between minor or even patch versions. Which means that even when I&apos;m creating small modules that are meant to be used as buildling blocks in other projects, I can&apos;t give them a flexible version range. Instead, I have to hard-code a specific version of Underscore into my dependencies if I want to be &lt;em&gt;sure&lt;/em&gt; it&apos;ll continue to work when future release come out. This isn&apos;t just hypothetical; we were saved in a few instances by having hardcoded to 1.6.0 when 1.7.0 came out.&lt;/p&gt;
&lt;p&gt;What else could we do? Well, some people try to circumvent the problem altogether by fishing out and including various helper functions directly in their modules. Or even &lt;a href=&quot;https://github.com/n1k0/backbone-events-standalone/blob/64f42b7f457e9cda63cbc599848200ba842a6039/backbone-events-standalone.js#L29-L85&quot;&gt;port a whole little mini-Underscore into their project&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;But that also seems less than ideal. Is &lt;em&gt;that&lt;/em&gt; partial implementation well-tested and cross-browser ready? Likely not.&lt;/p&gt;
&lt;h2 id=&quot;what-about-jquery&quot;&gt;&lt;a href=&quot;#what-about-jquery&quot; aria-label=&quot;what about jquery permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about jQuery?&lt;/h2&gt;
&lt;p&gt;Same thing, right? Except even the new, slimmer, sleeker 2.x version is five times bigger than underscore at 28kb (min+gzip). &lt;/p&gt;
&lt;p&gt;Again, by itself, maybe not a big deal. But what if all you need is a single &lt;code class=&quot;language-text&quot;&gt;addClass&lt;/code&gt; function for your small module? If feels silly to depend on the existence of a global &lt;code class=&quot;language-text&quot;&gt;$&lt;/code&gt; that can select elements and has an &lt;code class=&quot;language-text&quot;&gt;addClass&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;You may have seen sites like &lt;a href=&quot;http://youmightnotneedjquery.com/&quot;&gt;you might not need jQuery&lt;/a&gt; that try to show you how to do what jQuery does for them under the hood to encourage people not to depend on it. But that can &lt;a href=&quot;https://twitter.com/paul_irish/status/431584056883429376&quot;&gt;have some problems too&lt;/a&gt;. As it turns out, jQuery&apos;s implementation of &lt;code class=&quot;language-text&quot;&gt;addClass&lt;/code&gt; &lt;a href=&quot;https://github.com/jquery/jquery/blob/29838b6cab6f2e508f3e9692f32918c72b1a504b/src/attributes/classes.js#L11-L52&quot;&gt;is a bit more complex&lt;/a&gt; than the alternate that is suggested, and arguably for good reason.&lt;/p&gt;
&lt;h2 id=&quot;the-tiny-modules-philosophy&quot;&gt;&lt;a href=&quot;#the-tiny-modules-philosophy&quot; aria-label=&quot;the tiny modules philosophy permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The tiny modules philosophy&lt;/h2&gt;
&lt;p&gt;The whole approach of depending on a larger library or existence of a global goes a bit against the grain of the Node.js community at large. As the instigator behind &lt;a href=&quot;http://ampersandjs.com&quot;&gt;Ampersand.js&lt;/a&gt;, a clientside framework that aims to be the most flexible, composable option out there, it never felt right to me that we have Underscore 1.6.0 as a hard dependency of several of our modules, especially if we&apos;re only using a couple of methods in a given module.&lt;/p&gt;
&lt;p&gt;In the same way that we don&apos;t want to force you to use jQuery, a certain template language, or view layer in Ampersand, we don&apos;t want to pick your utility library, either! But, what choice do we have?&lt;/p&gt;
&lt;p&gt;What about &lt;a href=&quot;https://lodash.com/&quot;&gt;Lo-Dash&lt;/a&gt;? &lt;/p&gt;
&lt;p&gt;Well, conceptually it&apos;s not too far off. There&apos;s a CLI tool that will generate each of them as individual modules and all of those have been published to npm individually.&lt;/p&gt;
&lt;p&gt;But... it&apos;s not perfect either. For example, below is the dependency tree for &lt;a href=&quot;https://www.npmjs.org/package/lodash.bind&quot;&gt;lodash.bind&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;.
└── node_modules
    ├── lodash._createwrapper
    │   └── node_modules
    │       ├── lodash._basebind
    │       │   └── node_modules
    │       │       ├── lodash._basecreate
    │       │       │   └── node_modules
    │       │       │       ├── lodash._isnative
    │       │       │       └── lodash.noop
    │       │       ├── lodash._setbinddata
    │       │       │   └── node_modules
    │       │       │       ├── lodash._isnative
    │       │       │       └── lodash.noop
    │       │       └── lodash.isobject
    │       │           └── node_modules
    │       │               └── lodash._objecttypes
    │       ├── lodash._basecreatewrapper
    │       │   └── node_modules
    │       │       ├── lodash._basecreate
    │       │       │   └── node_modules
    │       │       │       ├── lodash._isnative
    │       │       │       └── lodash.noop
    │       │       ├── lodash._setbinddata
    │       │       │   └── node_modules
    │       │       │       ├── lodash._isnative
    │       │       │       └── lodash.noop
    │       │       └── lodash.isobject
    │       │           └── node_modules
    │       │               └── lodash._objecttypes
    │       └── lodash.isfunction
    └── lodash._slice&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It just seems a bit excessive for something simple. There&apos;s also lodash-node, which you then would require something in a nested path like: &lt;code class=&quot;language-text&quot;&gt;require(&amp;#39;lodash/underscore/bind&amp;#39;)&lt;/code&gt;. Which is pretty close, because now when we &lt;a href=&quot;http://ampersandjs.com/learn/npm-browserify-and-modules&quot;&gt;browserify it all&lt;/a&gt;, we&apos;ll end up only including the code it uses. But those paths are a bit unsightly and hard to remember, in my opinion.&lt;/p&gt;
&lt;h2 id=&quot;optimizing-for-done&quot;&gt;&lt;a href=&quot;#optimizing-for-done&quot; aria-label=&quot;optimizing for done permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Optimizing for &quot;done&quot;&lt;/h2&gt;
&lt;p&gt;But there&apos;s still some more subtlety there that&apos;s a bit annoying. Specifically, that the Lo-Dash and Underscore codebases will march on. Which means we might be at &lt;code class=&quot;language-text&quot;&gt;2.4.1&lt;/code&gt; if we used Lo-Dash right now, for example. So we would have to pick a version range to march along with. But when 3.x.x comes out, we&apos;ll have to update dependencies in order to get proper de-duping. I don&apos;t want to track Lo-Dash either, if all I want is a utility method, in most cases those seem like they should very rarely need any updating at all, right?&lt;/p&gt;
&lt;p&gt;Take for example the &lt;a href=&quot;https://www.npmjs.org/package/lodash.noop&quot;&gt;lodash.noop method&lt;/a&gt;. First, I&apos;m not convinced an empty function deserves to be its own module, but that aside, to me it feels odd that a module like this should ever have reached a SemVer version of 2.4.1. Of course, it happened this way because it was versioned with the rest of the project, but hopefully you see my point, there&apos;s no way that a noop function&apos;s API has changed. To be perfectly clear, I&apos;m not saying any of this as criticism of the Lo-Dash authors. They&apos;ve created a hugely successful project and are clearly a very brilliant bunch. In fact, &lt;a href=&quot;https://twitter.com/jdalton&quot;&gt;JDD&lt;/a&gt; has even given us some helpful feedback on some of our implementations. This is just an example of one tradeoff of thinking about a suite as a singular component rather than individual utilities.&lt;/p&gt;
&lt;p&gt;So what about this concept of &quot;done&quot; code? Is there such a thing? Well, APIs can certainly be done.&lt;/p&gt;
&lt;p&gt;Let&apos;s say I have an API for an &lt;code class=&quot;language-text&quot;&gt;addClass&lt;/code&gt; function that supported the following 3 APIs;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;class1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;class1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;class2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;el&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;array &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; classes&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I see no reason why that API contract would &lt;em&gt;ever&lt;/em&gt; have to change! That could be &lt;code class=&quot;language-text&quot;&gt;1.x.x&lt;/code&gt; version forever, right?&lt;/p&gt;
&lt;p&gt;The underlying implementation could change if a better/faster implementation was discovered. But that API contract should be able to be &lt;em&gt;done&lt;/em&gt;. Same is true of &lt;em&gt;most&lt;/em&gt; of these types of utility methods, especially if we make that an explicit goal.&lt;/p&gt;
&lt;p&gt;Imagine if we had a solid base-layer of well-tested, low-level, individually installable modules with &lt;em&gt;very stable&lt;/em&gt; APIs. Now &lt;em&gt;that&apos;s&lt;/em&gt; a shoulder you can stand on. It&apos;s easy to get caught up in pushing a bunch of new and updated code and constantly sitting and tweaking little things. Browsers are changing weekly, ES6 is coming down the pipe, change, change, change, change! It&apos;s awesome, but also a bit overwhelming to many. &lt;/p&gt;
&lt;p&gt;Don&apos;t get me wrong, I love an awesome bleeding-edge API as much as the next dev, I wrote the first version of &lt;a href=&quot;http://simplewebrtc.com/&quot;&gt;SimpleWebRTC&lt;/a&gt; several years ago, which was one of the first and most popular WebRTC libraries that I&apos;m aware of and thanks to the tireless stewardship of &lt;a href=&quot;https://twitter.com/hcornflower&quot;&gt;Fippo&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/lancestout&quot;&gt;Lance&lt;/a&gt; and many others it has been happily powering &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; and many other WebRTC projects for some time.&lt;/p&gt;
&lt;p&gt;I&apos;ve also spoken and written numerous times about building &lt;a href=&quot;https://www.youtube.com/watch?v=hrAssE8meRo&quot;&gt;apps that use the web to its fullest&lt;/a&gt;. Which is all to say, please don&apos;t mistake me for a Luddite.&lt;/p&gt;
&lt;p&gt;But I think we, the JavaScript community as a whole, have grown to undervalue stability. It&apos;s a boring concept, really. There&apos;s nothing exciting about it. But having a solid base platform on which to build means you&apos;re free to focus on the more interesting higher levels.&lt;/p&gt;
&lt;p&gt;As you&apos;ve probably guessed by now, we&apos;ve tried to tackle this problem. Not because we really &lt;em&gt;wanted&lt;/em&gt; to, but &lt;em&gt;because we wanted it to go away&lt;/em&gt;. I&apos;m not the only one, it seems. My friend &lt;a href=&quot;https://twitter.com/feross&quot;&gt;Feross&lt;/a&gt; apparently reached the same conclusion and split out &lt;a href=&quot;https://www.npmjs.org/package/run-auto&quot;&gt;the&lt;/a&gt; &lt;a href=&quot;https://www.npmjs.org/package/run-parallel&quot;&gt;most&lt;/a&gt; &lt;a href=&quot;https://www.npmjs.org/package/run-waterfall&quot;&gt;useful&lt;/a&gt; &lt;a href=&quot;https://www.npmjs.org/package/run-series&quot;&gt;methods&lt;/a&gt; from async.&lt;/p&gt;
&lt;p&gt;I&apos;m in no way claiming this approach is my idea, by any means. TJ Holowaychuck and a &lt;a href=&quot;https://github.com/orgs/component/people&quot;&gt;whole slew of other people&lt;/a&gt; have been doing this type of thing with &lt;a href=&quot;http://component.github.io/&quot;&gt;component&lt;/a&gt;. There are also other great examples &lt;a href=&quot;https://github.com/blakeembrey/change-case&quot;&gt;like this one&lt;/a&gt; by &lt;a href=&quot;https://twitter.com/blakeembrey&quot;&gt;Blake Embrey&lt;/a&gt; that share the same philosophy.&lt;/p&gt;
&lt;h2 id=&quot;the-challenges-of-tiny-modules&quot;&gt;&lt;a href=&quot;#the-challenges-of-tiny-modules&quot; aria-label=&quot;the challenges of tiny modules permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The challenges of tiny modules&lt;/h2&gt;
&lt;p&gt;Tiny module all the things! Independent modules, FTW! Right?!&lt;/p&gt;
&lt;p&gt;It works great for a handful of modules, but this approach is hard to scale. Turns out it&apos;s kind of a pain to manage and maintain &lt;a href=&quot;https://www.npmjs.com/~henrikjoreteg&quot;&gt;100+ modules&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is especially true in the happy-fun-land that is the clientside. Because for browser code, you really want some sort of automated cross-browser testing. So let&apos;s say, for instance, that you find a faster, better, service for doing cross-browser testing. If you have to go update 80 different GitHub repos with your new test setup and config in order to do it, realistically, you&apos;re just not going to bother.&lt;/p&gt;
&lt;p&gt;What if you want to add performance benchmarking, or otherwise change the structural elements, or update licenses of all your tiny modules? Fact is, the modularization is fighting against you at that point.&lt;/p&gt;
&lt;p&gt;So that&apos;s the maintenance side, but also it&apos;s a bit problematic as a user, because names. You have to remember that you created a module called &lt;code class=&quot;language-text&quot;&gt;extend-object&lt;/code&gt; or was it &lt;code class=&quot;language-text&quot;&gt;object-extend&lt;/code&gt;?! And of course you have to remember it exists to begin with, go find it, then remember how to use it. Hopefully you wrote some good docs. &lt;/p&gt;
&lt;p&gt;Less than ideal. &lt;/p&gt;
&lt;p&gt;When I used to do a bunch of jQuery it was pretty simple: go to &lt;a href=&quot;https://jquery.com/&quot;&gt;jQuery.com&lt;/a&gt; and look up what the  &lt;code class=&quot;language-text&quot;&gt;closest()&lt;/code&gt; method does. All in one, nice, cohesive site of releated stuff. &lt;/p&gt;
&lt;p&gt;That&apos;s also what&apos;s so nice about Underscore. You just go read the &lt;a href=&quot;http://underscorejs.org/&quot;&gt;simple concise docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We wanted something that dealt with all this. We wanted a way to handle small modules that was easier to manage, test, and document.&lt;/p&gt;
&lt;p&gt;So we made &lt;a href=&quot;http://amp.ampersandjs.com/&quot;&gt;amp&lt;/a&gt; and it works like this: &lt;/p&gt;
&lt;h3 id=&quot;independent-modules-in-a-single-github-repo&quot;&gt;&lt;a href=&quot;#independent-modules-in-a-single-github-repo&quot; aria-label=&quot;independent modules in a single github repo permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Independent Modules in a single GitHub repo&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/ampersandjs/amp&quot;&gt;GitHub repo&lt;/a&gt; contains a &lt;a href=&quot;https://github.com/AmpersandJS/amp/tree/master/modules&quot;&gt;module&lt;/a&gt; with a folder for each function. &lt;/p&gt;
&lt;p&gt;All the modules have the same basic structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the implementation&lt;/li&gt;
&lt;li&gt;the tests&lt;/li&gt;
&lt;li&gt;the package.json file&lt;/li&gt;
&lt;li&gt;the doc file&lt;/li&gt;
&lt;li&gt;the generated README&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-build-system&quot;&gt;&lt;a href=&quot;#the-build-system&quot; aria-label=&quot;the build system permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The build system&lt;/h3&gt;
&lt;p&gt;This is the brains of the operation. The shared build system that manages practically everything:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lets us have local modules require each other without messing with require paths before publishing&lt;/li&gt;
&lt;li&gt;Automatically re-writes &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; files for each module to list &lt;code class=&quot;language-text&quot;&gt;dependencies&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;devDependencies&lt;/code&gt; based on what&apos;s used in the code. It even alphabetizes keys in the JSON using &lt;a href=&quot;https://www.npmjs.com/package/fixpack&quot;&gt;fixpack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gives us a central place to update licenses, READMEs, etc.&lt;/li&gt;
&lt;li&gt;Installs hooks to make sure code is linted, and all modules have tests, docs, etc.&lt;/li&gt;
&lt;li&gt;Stubs out new files needed when adding a modules with a simple command.&lt;/li&gt;
&lt;li&gt;Lets us run DOM-dependent modules from the CLI using, tape, and PhantomJS.&lt;/li&gt;
&lt;li&gt;Generates new versions of the docs site.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I feel that this is one of the more interesting aspects of all of this and may well end up with a blog post of its own very soon.&lt;/p&gt;
&lt;h3 id=&quot;namespaced-package-names&quot;&gt;&lt;a href=&quot;#namespaced-package-names&quot; aria-label=&quot;namespaced package names permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Namespaced package names&lt;/h3&gt;
&lt;p&gt;They all start with &lt;code class=&quot;language-text&quot;&gt;amp-&lt;/code&gt;, so we can keep the module names as descriptive, and therefore as memorable as possible (hopefully) without dealing with too many name conflicts.&lt;/p&gt;
&lt;h3 id=&quot;testing&quot;&gt;&lt;a href=&quot;#testing&quot; aria-label=&quot;testing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Testing&lt;/h3&gt;
&lt;p&gt;Everything is cross-browser tested using a continuous integration system composed of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://travis-ci.org/AmpersandJS/amp&quot;&gt;Travis CI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://saucelabs.com/opensauce&quot;&gt;Sauce Labs&lt;/a&gt; - using their generous Open Sauce tools&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/defunctzombie/zuul&quot;&gt;zuul&lt;/a&gt; - to wire the two together&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://npmjs.org/package/tape&quot;&gt;tape&lt;/a&gt; - Substack&apos;s minimalistic test harness that produces &lt;a href=&quot;http://en.wikipedia.org/wiki/Test_Anything_Protocol&quot;&gt;TAP&lt;/a&gt; output that we pipe to &lt;a href=&quot;https://github.com/scottcorgan/tap-spec&quot;&gt;tap-spec&lt;/a&gt; for purdy colors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, each module can be tested independently or as part of the whole from the command line with a simple &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt;. It does this using PhantomJS.&lt;/p&gt;
&lt;h3 id=&quot;the-documentation&quot;&gt;&lt;a href=&quot;#the-documentation&quot; aria-label=&quot;the documentation permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The documentation&lt;/h3&gt;
&lt;p&gt;We generate a clean, easily searchable doc site: &lt;a href=&quot;http://amp.ampersandjs.com/&quot;&gt;http://amp.ampersandjs.com/&lt;/a&gt;. We did it as a single page to be as &lt;code class=&quot;language-text&quot;&gt;Cmd + f&lt;/code&gt; friendly as possible.&lt;/p&gt;
&lt;p&gt;It includes:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Function signature&lt;/li&gt;
&lt;li&gt;Docs&lt;/li&gt;
&lt;li&gt;Example usage&lt;/li&gt;
&lt;li&gt;Expandable sections where you can see the entire implementation and relevant test file right inline&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;other-details&quot;&gt;&lt;a href=&quot;#other-details&quot; aria-label=&quot;other details permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Other details&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;All the modules are published individually&lt;/li&gt;
&lt;li&gt;Docs are intentionally not in the READMEs so that we can update docs structure, etc. without having to publish patch versions just to get the npm version of the README updated.&lt;/li&gt;
&lt;li&gt;Strict SemVer with the goal of publishing a bunch of 1.0.0 versioned modules that optimized for being &quot;complete&quot; and requiring absolutely minimal updates. &lt;/li&gt;
&lt;li&gt;Since there&apos;s no bundling and they&apos;re all individual modules, the collection can keep growing over time and there&apos;s very little &quot;inclusion cost.&quot; So things that are currently relegated to underscore.contrib or used from jQuery can be included too.&lt;/li&gt;
&lt;li&gt;We&apos;ve got a pretty good start on it, and have ported many of the underscore methods (and related tests) we needed for Ampersand, but plan to continue to expand it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;but-why&quot;&gt;&lt;a href=&quot;#but-why&quot; aria-label=&quot;but why permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But why?!&lt;/h3&gt;
&lt;p&gt;This might all be a little ridiculous, but maybe it&apos;s also a little bit awesome? I know I&apos;ve wanted something like this to exist many times, and once devs get over their initial &quot;why another thing?!&quot; reaction and understand the stability goals, I&apos;ve found many people who have been wanting something like this, too.&lt;/p&gt;
&lt;p&gt;And hey, they good news is, if this isn&apos;t something you think is a good idea or don&apos;t want to use–fortunately, it&apos;s a big web out there with lots of options. Use what works for you. Tools are just tools; it&apos;s what you build with them that matters.&lt;/p&gt;
&lt;p&gt;I&apos;m &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; on Twitter. Also, I wrote a book about building maintainable JavaScript apps called &lt;a href=&quot;http://humanjavascript.com&quot;&gt;Human JavaScript&lt;/a&gt;, &lt;a href=&quot;http://andyet.com/training&quot;&gt;I teach JS&lt;/a&gt;, and in addition, if you liked this post odds are you&apos;ll want to &lt;a href=&quot;http://ampersandjs.com&quot;&gt;check out Ampersand.js&lt;/a&gt; as well. If you want to hang out with a bunch of people working with these tools, come join the &lt;a href=&quot;https://gitter.im/AmpersandJS/AmpersandJS&quot;&gt;project chat on Gitter&lt;/a&gt; or connect via IRC &lt;a href=&quot;https://irc.gitter.im/&quot;&gt;using the gitter bridge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See you on the Interwebz!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[WebRTC for the Web]]></title><description><![CDATA[We believe WebRTC is one of the most important technologies to hit the web in many years. There is a significant opportunity for WebRTC to…]]></description><link>https://blog.andyet.com/2014/12/19/webrtc-for-the-web/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/19/webrtc-for-the-web/</guid><pubDate>Fri, 19 Dec 2014 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We believe WebRTC is one of the most important technologies to hit the web in many years. There is a significant opportunity for WebRTC to help deliver on the promise of the open web—but for communication and collaboration.&lt;/p&gt;
&lt;p&gt;In several of our colleague Henrik Joreteg&apos;s talks the past couple years, he&apos;s said, &lt;em&gt;&quot;WebRTC needs more Open Web hackers!&quot;&lt;/em&gt; It&apos;s very true.&lt;/p&gt;
&lt;p&gt;But WebRTC is much more complicated than other browser APIs that web developers deal with.&lt;/p&gt;
&lt;p&gt;It seems, from our vantage point, like a large portion of the users of WebRTC have &lt;em&gt;not&lt;/em&gt; been Open Web hackers.&lt;/p&gt;
&lt;p&gt;We have no problem with companies and telcos using and adopting WebRTC (and have even helped companies like AT&amp;#x26;T to do so), but we feel that WebRTC still isn&apos;t accessible enough to a community of developers we care so much about: Open Web devs.&lt;/p&gt;
&lt;p&gt;When Henrik created &lt;a href=&quot;http://github.com/henrikjoreteg/simplewebrtc&quot;&gt;SimpleWebRTC&lt;/a&gt; two years ago, it aimed to help do this. Many people have created projects with it. But there is a bigger need than what SimpleWebRTC does.&lt;/p&gt;
&lt;p&gt;We&apos;ve found that doing WebRTC &lt;em&gt;very well&lt;/em&gt; requires a broad combination of tech expertise. It&apos;s easy enough to put together a WebRTC &lt;em&gt;demo&lt;/em&gt;, but shipping a real production quality product is no easy task.&lt;/p&gt;
&lt;p&gt;And as we&apos;ve worked on &lt;a href=&quot;http://talky.io&quot;&gt;Talky&lt;/a&gt; and other WebRTC applications, we&apos;ve found all kinds of challenging corners. Configuring TURN servers is hard. Having large group video conversations is hard. Native applications are hard. Command and control is hard. And having been designed as a more powerful low-level API, ORTC is going to be even harder for web developers to grasp.&lt;/p&gt;
&lt;p&gt;Because consulting is the core of &amp;#x26;yet&apos;s business, we&apos;ve built a team capable of solving these problems. But we strongly believe it shouldn&apos;t require a specialized team to build something great with WebRTC.&lt;/p&gt;
&lt;p&gt;WebRTC needs better documentation, easier tools, and clearer onboarding.&lt;/p&gt;
&lt;p&gt;We are grateful for browser vendors&apos; work in adopting this ambitious spec. We are grateful for their efforts to interoperate and participate in standards. But we can&apos;t rely on them to bridge this gap for us.&lt;/p&gt;
&lt;p&gt;The imminent arrival of ORTC and IE support represents a pivotal moment in WebRTC. While this is going to increase complexity in the ecosystem, it&apos;s also a chance to get right a lot of what hasn&apos;t worked very well so far for WebRTC in terms of empowering web developers to build with it.&lt;/p&gt;
&lt;p&gt;We need a community effort that&apos;s fully independent from browser vendors to do that. And this effort needs to be openly governed.&lt;/p&gt;
&lt;p&gt;We need to embrace players contributing useful technology to the WebRTC ecosystem, and encourage everyone to find commonalities and ways to collaborate in our open source code, so we can put less energy toward solved problems and more towards the hard stuff.&lt;/p&gt;
&lt;p&gt;A rising tide floats all boats—but the WebRTC sea level is still desperately low.&lt;/p&gt;
&lt;p&gt;Here&apos;s how we propose raising that level:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;a href=&quot;https://github.com/webrtcftw&quot;&gt;an open GitHub repo&lt;/a&gt; to organize, discuss, and prioritize efforts.&lt;/li&gt;
&lt;li&gt;Reach out to the web developer community and find out what developers need.&lt;/li&gt;
&lt;li&gt;Form a group of developers to discuss and advocate for specific improvements to browser APIs, using collaborative resources like &lt;a href=&quot;http://iswebrtcreadyyet.com&quot;&gt;iswebrtcreadyyet.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Set up an event in early 2015 to rapidly speed up discussion and collaboration.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We&apos;re calling this effort &quot;WebRTC for the Web,&quot; we&apos;re organizing it at &lt;a href=&quot;https://github.com/webrtcftw&quot;&gt;github.com/webrtcftw&lt;/a&gt; alongside a lot of other amazing folks who have led the way for WebRTC. Whatever your skill level with WebRTC, we&apos;d love to have you involved in the discussion. It&apos;s been awesome to see some of the conversations so far.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What do you say? Are you in?&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[CoreOS: Etcd in Docker containers]]></title><description><![CDATA[At &yet we have become big fans of CoreOS and Docker, and we've recently moved a bunch of our Node applications there. We wanted to share a…]]></description><link>https://blog.andyet.com/2014/12/17/etcd-in-docker-containers/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/17/etcd-in-docker-containers/</guid><pubDate>Wed, 17 Dec 2014 17:30:00 GMT</pubDate><content:encoded>&lt;p&gt;At &amp;#x26;yet we have become big fans of &lt;a href=&quot;https://coreos.com/&quot;&gt;CoreOS&lt;/a&gt; and &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt;, and we&apos;ve recently moved a bunch of our Node applications there. &lt;/p&gt;
&lt;p&gt;We wanted to share a little tidbit for something that seems like it should be easy, but ended up being a minor stumbling block: making CoreOS&apos;s &lt;a href=&quot;https://github.com/coreos/etcd/&quot;&gt;Etcd&lt;/a&gt; cluster available in Docker.&lt;/p&gt;
&lt;p&gt;Here&apos;s a little background for those not up to speed on CoreOS or Etcd. CoreOS bills itself as &quot;Linux for Massive Server Deployments.&quot; CoreOS is usually deployed with Etcd, &quot;a highly-available key value store for shared configuration and service discovery,&quot; giving servers in a cluster the ability to share configuration data. We have been using Etcd and Confd for some time, so we naturally thought: &quot;wouldn&apos;t it be cool to configure applications and services within Docker from Etcd?&quot;&lt;/p&gt;
&lt;p&gt;This can be easily accomplished by passing an environment variable to Docker at runtime and tweaking a few iptables rules. CoreOS makes the Etcd HTTP API available on its private IP address at port 4001 by default. CoreOS also sets an environment variable called &lt;code class=&quot;language-text&quot;&gt;$COREOS_PRIVATE_IPV4&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;/etc/hosts&lt;/code&gt; with said IP. Fortunately, Docker is networked to the host&apos;s private IP, so this is the easiest point of access for Etcd.&lt;/p&gt;
&lt;p&gt;Here&apos;s a sample unit file for Fleet and Dockerfile with the needed configuration to bring it all together:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unit File&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[Unit]
Description=Node App
Requires=docker.service

[Service]
EnvironmentFile=/etc/environment
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill node-app
ExecStartPre=-/usr/bin/docker rm node-app
ExecStartPre=/usr/bin/docker pull {{docker_registry}}/node-app
ExecStart=/usr/bin/docker run --rm=true --name=node-app -P -e COREOS_PRIVATE_IPV4=${COREOS_PRIVATE_IPV4} registry/node-app
ExecStop=/usr/bin/docker stop node-app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are two relevant parts of the unit file to make it all work. First, &lt;code class=&quot;language-text&quot;&gt;EnvironmentFile=/etc/environment&lt;/code&gt; must be set, otherwise &lt;code class=&quot;language-text&quot;&gt;${COREOS_PRIVATE_IPV4}&lt;/code&gt;  will be empty. The second is setting &lt;code class=&quot;language-text&quot;&gt;-e COREOS_PRIVATE_IPV4=${COREOS_PRIVATE_IPV4}&lt;/code&gt; so your container also has access to the private IP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;FROM debian:wheezy
MAINTAINER Marcus Stong, marcus@andyet.net
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y curl
CMD echo &amp;quot;Etcd Version: $(curl http://${COREOS_PRIVATE_IPV4}:4001/version)&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This Dockerfile returns the CoreOS Etcd version to confirm connectivity. In your real Docker containers, your applications can access Etcd by using the environment variable &lt;code class=&quot;language-text&quot;&gt;$COREOS_PRIVATE_IPV4&lt;/code&gt; in the connection string.&lt;/p&gt;
&lt;p&gt;Don&apos;t forget that if you&apos;re running a command in Docker as the core user in an ssh session, you have to run &lt;code class=&quot;language-text&quot;&gt;source /etc/environment&lt;/code&gt; first.&lt;/p&gt;
&lt;h2 id=&quot;what-about-iptables&quot;&gt;&lt;a href=&quot;#what-about-iptables&quot; aria-label=&quot;what about iptables permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What About iptables?&lt;/h2&gt;
&lt;p&gt;If you&apos;re using iptables in CoreOS (&lt;a href=&quot;https://blog.andyet.com/2014/09/09/taming-iptables&quot;&gt;hopefully you are&lt;/a&gt;) you&apos;ll need to include some additional rules. Assuming a default DROP policy on the INPUT, OUTPUT, and FORWARD tables, those rules would look like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;#!/bin/bash
iptables -A FORWARD -i docker0 -o eth1 -j ACCEPT
iptables -A FORWARD -o docker0 -i eth1 -j ACCEPT

iptables -A INPUT  -i docker0 -p tcp --dport 4001 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o docker0 -p tcp --sport 4001 -m state --state ESTABLISHED -j ACCEPT

iptables -A OUTPUT -o eth1 -p tcp --dport 4001 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT  -i eth1 -p tcp --sport 4001 -m state --state ESTABLISHED -j ACCEPT

iptables -A INPUT  -i eth1 -p tcp --dport 4001 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o eth1 -p tcp --sport 4001 -m state --state ESTABLISHED -j ACCEPT&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a href=&quot;#conclusion&quot; aria-label=&quot;conclusion permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;And there you go! &lt;/p&gt;
&lt;p&gt;You should now be well on your way to using the Etcd goodness that makes CoreOS so attractive in the first place!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The yeti &you]]></title><description><![CDATA[Hey folks! It's the holiday season, the goose is getting fat, the decorations are filling the air with glimmery goodness, and the yeti is…]]></description><link>https://blog.andyet.com/2014/12/16/the-yeti-and-you/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/16/the-yeti-and-you/</guid><pubDate>Tue, 16 Dec 2014 14:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Hey folks! It&apos;s the holiday season, the goose is getting fat, the decorations are filling the air with glimmery goodness, and the yeti is plodding through the snow with gifts for all its web-loving friends. &lt;/p&gt;
&lt;p&gt;But oh no! What if it doesn&apos;t know where to go?!&lt;/p&gt;
&lt;p&gt;The yeti could shower its gifts onto the twitters, sure, but then how would it know you received it? It could leave it on this here blog, but what if–gasp–you FORGET? You might accidentally leave the yeti&apos;s gift out in the cold, cold snow where it could develop abandonment issues.&lt;/p&gt;
&lt;p&gt;Hang on hang on. I have an idea. What about &amp;#x26;you?&lt;/p&gt;
&lt;p&gt;For those of you who don&apos;t know about it yet, &amp;#x26;you is a place where we discuss the things we love, the things we&apos;re interested in, and (most importantly) the things we&apos;re curious about. And because of that, we get to have conversations with people like you, too.&lt;/p&gt;
&lt;p&gt;Because we love you folks out there in internet-land.&lt;/p&gt;
&lt;p&gt;(And so does the yeti.)&lt;/p&gt;
&lt;p&gt;In fact (and shhhh! this part is a secret) we like you so much that we have a surprise in store for all of our &amp;#x26;you friends. So sign up below and keep an eye on your inbox this week for something special. Something mysterious. Something for all of us.&lt;/p&gt;
&lt;p&gt;(And you!)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Something Greater than Artifice: Indie Book of the Year]]></title><description><![CDATA[First: so hey, it looks like our novel, Something Greater than Artifice, was selected as a Kirkus Reviews Indie Book of the Year! Which is…]]></description><link>https://blog.andyet.com/2014/12/15/indie-book-of-the-year/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/15/indie-book-of-the-year/</guid><pubDate>Mon, 15 Dec 2014 12:30:00 GMT</pubDate><content:encoded>&lt;p&gt;First: so hey, it looks like our novel, &lt;a href=&quot;https://www.kirkusreviews.com/book-reviews/mike-speegle/something-greater-than-artifice/&quot;&gt;&lt;em&gt;Something Greater than Artifice&lt;/em&gt;&lt;/a&gt;, was selected as a Kirkus Reviews Indie Book of the Year! &lt;/p&gt;
&lt;p&gt;Which is nice. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://d3eoifnsb8kxf0.cloudfront.net/14q1/img/best_of/2014/badge_indie_100x129.jpg&quot; alt=&quot;So are badges&quot;&gt;&lt;/p&gt;
&lt;p&gt;Second: which means that the message &lt;em&gt;behind&lt;/em&gt; the book is getting out there. &lt;/p&gt;
&lt;p&gt;Which is even better. &lt;/p&gt;
&lt;p&gt;Because &lt;em&gt;Something Greater than Artifice&lt;/em&gt;, while being a sci-fi romp through the countryside featuring futuristic tech and faceless villains and people getting punched &lt;em&gt;square in the face&lt;/em&gt;, represents something greater than the sum of its parts. &lt;/p&gt;
&lt;h2 id=&quot;because-silos&quot;&gt;&lt;a href=&quot;#because-silos&quot; aria-label=&quot;because silos permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Because silos&lt;/h2&gt;
&lt;p&gt;We at &amp;#x26;yet believe in a free and open web, and we support that idea by making open source projects based around the idea that siloization is bad, and that sharing is good. And sometimes we make cool apps like &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; and share &lt;a href=&quot;https://github.com/otalk&quot;&gt;all the fundamental components&lt;/a&gt; we used to make it! &lt;/p&gt;
&lt;p&gt;And sometimes we write books about it. &lt;/p&gt;
&lt;p&gt;For those of you who don’t know, &lt;em&gt;Something Greater than Artifice&lt;/em&gt; is a straight-up allegory for open source realtime technologies, and what will happen if we let the silos win. &lt;/p&gt;
&lt;h3 id=&quot;so-why-are-silos-bad&quot;&gt;&lt;a href=&quot;#so-why-are-silos-bad&quot; aria-label=&quot;so why are silos bad permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So why are silos bad?&lt;/h3&gt;
&lt;p&gt;Well...they&apos;re not always bad. Not at first. Silos are just storage units, really, just like the ones you&apos;d see on a farm – big containers for &lt;em&gt;just one kind of thing&lt;/em&gt; (which isn&apos;t inherently bad, either).&lt;/p&gt;
&lt;p&gt;But when it comes to technology, sometimes those silos are less like big ol&apos; grain canisters and more like the Prince John from the old Robin Hood movies: taking everything of value and sealing it up behind an impassable wall. Everything belongs in its place, separated from everything else. Nothing escapes and nothing travels in between. Not even ideas. &lt;/p&gt;
&lt;p&gt; And like Prince John, the people who own these silos don&apos;t like competition. They want to snap up anything that doesn&apos;t fit into their stratified, hypercapitalist worldview and make it go away forever. They want everything to be the same, and they want to own it.&lt;/p&gt;
&lt;p&gt; And we&apos;re not cool with that.&lt;/p&gt;
&lt;p&gt;(Which is why we call the bad guys SILOS. Subtle, right? Then just wait for the Snowden joke.)&lt;/p&gt;
&lt;p&gt; So if you wanna live indie and silo-free, you might wanna check out this book. But you don’t have to take my word for it.&lt;/p&gt;
&lt;h2 id=&quot;but-also-because-people&quot;&gt;&lt;a href=&quot;#but-also-because-people&quot; aria-label=&quot;but also because people permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But also because people&lt;/h2&gt;
&lt;p&gt;AND NOW, A PARABLE: A couple years back, my wife and I were watching a vapid reality TV program. One of the participants in the show, a professional public figure, had her memoirs written by a ghost writer. When her friends find out, they mock her for not having written her own book.&lt;/p&gt;
&lt;p&gt;Her response? “It takes a village to write a book.”&lt;/p&gt;
&lt;p&gt;My response to &lt;em&gt;that?&lt;/em&gt; Mostly cussing. &lt;/p&gt;
&lt;p&gt;Because at the time I saw the compositional process as an isolated one. Hell, I was friggin’ Shakespeare as far as I was concerned. Or at least a less-mathematically-obsessed Neal Stephenson. Yes indeed, some men are an island, and that island was me. &lt;/p&gt;
&lt;p&gt;Yeah, no. &lt;/p&gt;
&lt;p&gt;But I didn’t realize it until I started working on &lt;em&gt;SGtA&lt;/em&gt; how much I rely on the people around me. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://andyet.com/team/adam&quot;&gt;Adam&lt;/a&gt;, telling me in no uncertain terms to ax former character Ernesto, after which fan-favorite Ivan grew in his place.&lt;/p&gt;
&lt;p&gt;Lise, my editor, patiently explaining that I can only use the term “byzantine” so many times. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://andyet.com/team/jenn&quot;&gt;Jenn&lt;/a&gt;, painstakingly outlining every single chapter in the book in order to find the right places to insert section breaks and–in turn–&lt;a href=&quot;https://andyet.com/team/amy&quot;&gt;Amy’s&lt;/a&gt; glyphs and gorgeous cover. &lt;/p&gt;
&lt;p&gt;A lot of people worked very hard on this book. But then, that’s the indie spirit isn’t it? It’s not about doing everything yourself; it’s about coming together with the people around you, those stalwart few who actually give a damn about one another, and making something greater. &lt;/p&gt;
&lt;p&gt;(Which is kind of what &amp;#x26;yet’s all about, if you ask me)&lt;/p&gt;
&lt;p&gt;So yeah! If you’ve read the book, drop on by Amazon and &lt;a href=&quot;http://www.amazon.com/Something-Greater-than-Artifice-Speegle-ebook/dp/B00FUF8X0Y/ref=asap_B008RCI3FM?ie=UTF8&quot;&gt;tell us what you thought of it&lt;/a&gt;. If you haven&apos;t you can always pick up a copy &lt;a href=&quot;http://www.amazon.com/Something-Greater-than-Artifice-Speegle-ebook/dp/B00FUF8X0Y/ref=asap_B008RCI3FM?ie=UTF8&quot;&gt;here&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;OR...if you wanna go full indie, skip the silos and get it &lt;a href=&quot;http://www.0s-1s.com/shelves/something-greater-than-artifice&quot;&gt;here&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[I accidentally learned something from high schoolers]]></title><description><![CDATA[Enterprise Week is the name of a week-long activity for high school seniors in the Pasco School District. It's loosely affiliated with…]]></description><link>https://blog.andyet.com/2014/12/12/what-eric-learned/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/12/what-eric-learned/</guid><pubDate>Fri, 12 Dec 2014 16:15:00 GMT</pubDate><content:encoded>&lt;p&gt;Enterprise Week is the name of a week-long activity for high school seniors in the &lt;a href=&quot;http://www.psd1.org/site/default.aspx?PageID=1&quot;&gt;Pasco School District&lt;/a&gt;. It&apos;s loosely affiliated with &lt;a href=&quot;http://www.wbw.org/&quot;&gt;Washington Business Week&lt;/a&gt;, which is our state&apos;s incarnation of a program that many states run aimed at exposing young folks to the business world.&lt;/p&gt;
&lt;p&gt;During Enterprise Week, every senior from the three high schools in the district are pulled out of school and dropped into their &quot;offices&quot; in a local convention center. Volunteers from the local business community are asked to be a &quot;Company Advisor&quot; for each group of about a dozen students. I volunteered to be one, and I had no idea what to expect.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/eric-1-2.JPG&quot; alt=&quot;Luckily there was a manual.&quot;&gt;&lt;/p&gt;
&lt;p&gt;The first, most important thing a Company Advisor (CA) should do, we were told, is to sit back and let the kids do the work. Each &quot;company&quot; would have a CEO, a COO, and heads of other various departments, much as you&apos;d expect from a real business. It was the CA&apos;s job to select the CEO, and then let them run the show.&lt;/p&gt;
&lt;p&gt;Once the CEO was selected for my group and tasks and responsibilities were communicated, work began.&lt;/p&gt;
&lt;p&gt;Remember when you were a high school senior? So you know what &quot;work began&quot; really means. This was not unexpected though, previous CAs and the faculty running the program set the expectation that the first day and a half or so would be wandering, confusing, and disorganized; that the kids would be largely flippant about it.&lt;/p&gt;
&lt;p&gt;And it was, and they were.&lt;/p&gt;
&lt;p&gt;But first, a quick side trip to look at a couple innate power structures at play here.&lt;/p&gt;
&lt;p&gt;These kids are used to sitting in a room with an adult in the front telling them what they need to be learning and assigning them tasks with due dates. While some learning institutions take different approaches, this generalization is true of the Pasco high schools.&lt;/p&gt;
&lt;p&gt;The second structure they&apos;re familiar with is how business structures are most commonly portrayed in the media: a powerful and/or hyper-energetic CEO having micro-control over every aspect of her business, with a hierarchical approach to delegating duties, responsibilities, and tasks very heavy-handedly.&lt;/p&gt;
&lt;p&gt;So there I sat in an &quot;office&quot; with tables and chairs and 12 kids waiting to react to authority&apos;s instructions.&lt;/p&gt;
&lt;p&gt;The first day, I said: here&apos;s your packet of information, go for it. And then I sat down and read emails or I left the &quot;office&quot; area altogether. Suffice it to say, the first day ended with a lot of unused time. The students got started on a few things, but largely ignored the idea that it was up to them to find out and understand what their tasks and due dates were. They were waiting to be told what to do, when to do it, and how to do it.&lt;/p&gt;
&lt;p&gt;In the real world, there&apos;s not a lot of hand-holding.&lt;/p&gt;
&lt;p&gt;But that is the point of Enterprise Week: a healthy serving of business in the real world.&lt;/p&gt;
&lt;p&gt;Sometime during the second day I realized there was another way to motivate the CEO and the team without resorting to those power structures they&apos;re used to. This was supposed to be the real world after all, and if there&apos;s one thing I&apos;ve learned from experience, it&apos;s that the threat of losing your job and arbitrary deadlines are the worst kind of motivators.&lt;/p&gt;
&lt;p&gt;Instead, I got them excited about whatever progress they &lt;em&gt;were&lt;/em&gt; making. I encouraged them when they finished something or came up with a plan they were excited about. I congratulated them when they did well, I told them to put more stock in the fact they tried something even if they failed, and I upped my energy level about the activities in general. I realized they were following my lead and it had nothing to do with explicit instructions I gave them, but everything to do with how I was acting and how I reacted to things they were doing.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/eric-1.JPG&quot; alt=&quot;Amazing what people can do when you lead from the ground.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Much to my surprise, it worked! By the end of the week, they had done some pretty awesome work and they got third place overall in their division!&lt;/p&gt;
&lt;p&gt;More importantly, they were enthusiastic about what they were doing. They were trying, they had each found a way within themselves to feel good about contributing. And I&apos;m pretty sure they learned something about the responsibility and power they have over the outcome of their own lives.&lt;/p&gt;
&lt;p&gt;Sure, in an environment where we all knew that I was in the position of &quot;authority&quot; or &quot;having expertise,&quot; they could&apos;ve been responding to that. But I don&apos;t think so. I think it had more to do with how I interacted with them.&lt;/p&gt;
&lt;p&gt;So my accidental realization is that there&apos;s no reason I can&apos;t do this for my family, friends, colleagues, and other peers. Of course, I&apos;ve kind of thought that, but never felt like I could be successful at it. Enterprise Week, at whatever level, showed me I &lt;em&gt;can&lt;/em&gt; do that. People are people, with generally similar needs (hello, Mr. Maslow), regardless of age. When it comes to esteem and self-actualization, they want to be appreciated, encouraged, and excited. &lt;/p&gt;
&lt;p&gt;I&apos;ve found throughout my life that most people don&apos;t come to this realization completely independently. I certainly didn&apos;t. We need outside reinforcement along the way. &lt;/p&gt;
&lt;p&gt;It&apos;s autonomy, but in a very deep, self-aware way. So many people think autonomy is having the power to choose between A, B, or C, but the autonomy I&apos;m talking about here is the ability to see that those aren&apos;t the only options. The real problem they need to focus on is how to achieve &quot;D. Any, all, or none of the above.&quot; Without the confidence that those choice sets are completely up to them, they won&apos;t try. They&apos;ll select one of the provided answers and go with that. That might be fine and lead to sufficient and &quot;normal&quot; life outcomes, but that usually means just going through some pre-determined motions and accepting some marketing department&apos;s description of &quot;a happy life.&quot;&lt;/p&gt;
&lt;p&gt;That is not an existence I want and I&apos;d argue no one wants, but you have to see for yourself that you have the power to do something you &lt;em&gt;truly&lt;/em&gt; want to do, and you must understand that living someone else&apos;s dream is not required.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/eric-2.JPG&quot; alt=&quot;And then sometimes they come up with some dreams of their own.&quot;&gt;&lt;/p&gt;
&lt;p&gt;I deeply want people to feel that way. I deeply want people to want that for themselves. But I can&apos;t force them to. I can&apos;t assign it to them as a task. I have to awaken the underlying motivations and stoke those such that people can find it and see it and feel it for themselves! And it&apos;s for that reason that I want to do way more of what I learned I&apos;m very capable of: encourage, support, and be extremely positive about other people&apos;s abilities. I believe those are the things that will put people on the path to self-discovery. And that is my passion, so I&apos;m gonna do it.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[FFConf: A Single Page Story]]></title><description><![CDATA[Henrik follows up on his "Opinionated rundown of JS frameworks" blog post with a presentation at FFConf, in which he explored topics related…]]></description><link>https://blog.andyet.com/2014/12/11/a-single-page-story/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/11/a-single-page-story/</guid><pubDate>Thu, 11 Dec 2014 11:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://andyet.com/team/henrik&quot;&gt;Henrik&lt;/a&gt; follows up on his &quot;Opinionated rundown of JS frameworks&quot; &lt;a href=&quot;http://blog.andyet.com/2014/08/13/opinionated-rundown-of-js-frameworks&quot;&gt;blog post&lt;/a&gt; with a presentation at &lt;a href=&quot;https://twitter.com/ffconf&quot;&gt;FFConf&lt;/a&gt;, in which he explored topics related to single-page apps, including: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Should we build apps that &lt;em&gt;require&lt;/em&gt; JavaScript to run&lt;/li&gt;
&lt;li&gt;What is a &quot;native web app&quot;?&lt;/li&gt;
&lt;li&gt;What about progressive enhancement?&lt;/li&gt;
&lt;li&gt;The performance implications of clientside apps&lt;/li&gt;
&lt;li&gt;Twitter’s move away from clientside back to server-rendered&lt;/li&gt;
&lt;li&gt;The two classes of web apps&lt;/li&gt;
&lt;li&gt;User expectations of modern applications&lt;/li&gt;
&lt;li&gt;Installable web apps&lt;/li&gt;
&lt;li&gt;True offline support for web apps: ServiceWorker&lt;/li&gt;
&lt;li&gt;Isomorphic (dual-rendered) applications&lt;/li&gt;
&lt;li&gt;Picking tools for a rapidly changing environment&lt;/li&gt;
&lt;li&gt;Optimizing for change&lt;/li&gt;
&lt;li&gt;Building for the future of the web&lt;/li&gt;
&lt;/ul&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/hrAssE8meRo&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;</content:encoded></item><item><title><![CDATA[Video codecs past, present, and future]]></title><description><![CDATA[Yesterday Fippo talked about applying the principles of the open web to realtime communication with WebRTC. Consider this post the first…]]></description><link>https://blog.andyet.com/2014/12/11/video-codecs-past-present-future/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/11/video-codecs-past-present-future/</guid><pubDate>Thu, 11 Dec 2014 09:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Yesterday Fippo &lt;a href=&quot;https://blog.andyet.com/2014/12/10/webrtc-and-the-web-we-want&quot;&gt;talked about&lt;/a&gt; applying the &lt;a href=&quot;http://tantek.com/2010/281/b1/what-is-the-open-web&quot;&gt;principles of the open web&lt;/a&gt; to realtime communication with WebRTC. Consider this post the first installment of providing in-depth descriptions of what that means in practice.&lt;/p&gt;
&lt;h3 id=&quot;where-codecs-fit-in&quot;&gt;&lt;a href=&quot;#where-codecs-fit-in&quot; aria-label=&quot;where codecs fit in permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Where codecs fit in&lt;/h3&gt;
&lt;p&gt;A key component of realtime audio and video systems (like &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt;) consists of methods for encoding the light waves and sound waves that our eyes and ears can understand into digital information that computers can process. Such a method is called a codec (shorthand for code/decode).&lt;/p&gt;
&lt;p&gt;Because there are many different audio codecs and video codecs, if we want interoperability, then it&apos;s important for different software implementations to &quot;speak the same language&quot; by having at least one codec in common. In the parlance of industry standards, such a codec is specified as &quot;mandatory to implement&quot; or MTI (often an MTI codec is a lowest common denominator, but software can use better codecs if available - a model that has also worked well for cipher suites in SSL/TLS and other technologies.)&lt;/p&gt;
&lt;p&gt;Unfortunately, because a lot of big companies have been granted a huge number of patents over codec technologies (and often jealously guard those patents under restrictive licenses), it can be difficult to settle on one MTI audio codec or video codec for communication over the Internet.&lt;/p&gt;
&lt;p&gt;In the case of audio, way back in 2009 I helped spearhead an effort at the Internet Engineering Task Force (IETF) to create a patent-clear and technically superior audio codec optimized for the Internet. &lt;/p&gt;
&lt;p&gt;In a spirit of true collaboration, core developers from Skype, Xiph.org, and other teams came together and combined the best of the Silk and CELT codecs to produce something that was better than the sum of its parts. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The result was &lt;a href=&quot;http://www.opus-codec.org/&quot;&gt;Opus&lt;/a&gt;, which has become the go-to audio codec for Internet voice apps&lt;/strong&gt; and the primary &lt;a href=&quot;http://datatracker.ietf.org/doc/draft-ietf-rtcweb-audio/&quot;&gt;MTI audio codec for WebRTC&lt;/a&gt; (yes, the old G.711 codec is also mandatory to implement in WebRTC, but primarily for interoperability with legacy systems - Opus is the codec that matters here).&lt;/p&gt;
&lt;h3 id=&quot;video-killed-the-audio-star&quot;&gt;&lt;a href=&quot;#video-killed-the-audio-star&quot; aria-label=&quot;video killed the audio star permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Video killed the audio star&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;In the case of video, the story is not so happy.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For almost three years now, the RTCWEB Working Group at the IETF has been fighting on and off about which video codec to specify as mandatory to implement. There have been two main contenders in this battle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;VP8&lt;/strong&gt;, proposed by Google and currently implemented by Google Chrome, Mozilla Firefox, Opera and the open source &lt;a href=&quot;http://webrtc.org&quot;&gt;webrtc.org stack&lt;/a&gt; provided by Google. Google claims it is not subject to patent licenses or royalties.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;H.264&lt;/strong&gt;, currently supported by Firefox through a &lt;a href=&quot;http://www.openh264.org/&quot;&gt;plugin&lt;/a&gt; provided by Cisco. H.264 is subject to royalties under certain conditions (which are avoided by Firefox in a clever way). It is a widely established codec supported in hardware such as phones, switches, PBXs, and the like.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The VP8 and H.264 camps have been at odds for years, and it appeared that a solution would never be found. Some folks even proposed the use of H.261, an ancient video codec that appears to be patent-clear, because at least everyone could deploy it without fear of licenses and royalties.&lt;/p&gt;
&lt;h1 id=&quot;a-new-hope&quot;&gt;&lt;a href=&quot;#a-new-hope&quot; aria-label=&quot;a new hope permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A new hope?&lt;/h1&gt;
&lt;p&gt;Yet at the IETF meeting a few weeks ago in Honolulu, a &lt;a href=&quot;http://www.ietf.org/mail-archive/web/rtcweb/current/msg13432.html&quot;&gt;novel proposal&lt;/a&gt; emerged and quickly received broad support among the browser vendors that currently implement WebRTC. &lt;/p&gt;
&lt;p&gt;The compromise is that WebRTC &quot;user agents&quot; (browsers like Chrome and Firefox) and &quot;devices&quot; (apps like &lt;a href=&quot;https://itunes.apple.com/app/talky-free-video-conferencing/id882057960&quot;&gt;Talky iOS&lt;/a&gt;) are supposed to implement &lt;em&gt;both&lt;/em&gt; VP8 and H.264. &lt;strong&gt;Thus there will be at least one codec which all participants in a video chat can use.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;building-something-better&quot;&gt;&lt;a href=&quot;#building-something-better&quot; aria-label=&quot;building something better permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Building something better&lt;/h3&gt;
&lt;p&gt;That&apos;s all fine, and I&apos;m not about to rain on this particular parade.&lt;/p&gt;
&lt;p&gt;However, I have to ask: &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Is this really the best we can do for the open web?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Far from it.&lt;/p&gt;
&lt;p&gt;What we need is a truly open and technically superior codec, like Opus but for video.&lt;/p&gt;
&lt;p&gt;In 2012 I once again worked with proponents of open codecs at the IETF (including the folks working on &lt;a href=&quot;https://xiph.org/daala/&quot;&gt;Daala&lt;/a&gt;, this time in an attempt to form a working group devoted to creation of a standard video codec. Sadly, that effort did not bear fruit.&lt;/p&gt;
&lt;p&gt;Yet.&lt;/p&gt;
&lt;p&gt;But I take the long view, perhaps because I&apos;ve been working on open communication technologies for 15 years, ever since I joined the Jabber instant messaging project in late 1999. &lt;/p&gt;
&lt;p&gt;The way I see it, 15 years from now we&apos;ll probably still be using WebRTC, but we won&apos;t be using creaky old codecs like H.264 and VP8. By then, I&apos;m confident that we&apos;ll have a technically superior and truly open video codec. &lt;/p&gt;
&lt;p&gt;Paradoxically, the Great Video Compromise worked out in Honolulu might even move us a bit closer in that direction, despite the fact that it seems to entrench H.264 and VP8 forever. &lt;/p&gt;
&lt;p&gt;As my former Cisco colleague Mo Zanaty &lt;a href=&quot;http://www.ietf.org/mail-archive/web/rtcweb/current/msg13802.html&quot;&gt;pointed out&lt;/a&gt;, supporting two video codecs also entails support for codec negotiation, capabilities discovery, and other technical features that will make it easier for software to handle emerging codecs such as VP9 (&lt;a href=&quot;https://blog.andyet.com/2014/11/24/hello-there-vp9&quot;&gt;recently deployed in Chrome&lt;/a&gt;) and H.265, as well as future codecs we can only dream about today.&lt;/p&gt;
&lt;p&gt;So am I enthusiastic about supporting both VP8 and H.264 in Talky? Not really. &lt;strong&gt;But it&apos;s the best we can do right now, until those of us who care about the open web build something better.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Maybe ask me again in 15 years. :-)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[WebRTC and the Web we want]]></title><description><![CDATA[There's a lot of talk about this topic of "the web we want," and a lot of it has focused around WebRTC lately.I have been working with…]]></description><link>https://blog.andyet.com/2014/12/10/webrtc-and-the-web-we-want/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/10/webrtc-and-the-web-we-want/</guid><pubDate>Wed, 10 Dec 2014 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There&apos;s a lot of talk about this topic of &quot;the web we want,&quot; and a lot of it has focused around WebRTC lately.&lt;/p&gt;
&lt;p&gt;I have been working with WebRTC since mid-2012, both in the Chrome and Firefox browsers, as well as the native webrtc.org library. So far I have filed more than sixty issues in the &lt;a href=&quot;http://code.google.com/p/webrtc/issues/list&quot;&gt;WebRTC project issue tracker&lt;/a&gt; and the Chrome bugtracker. I&apos;m especially proud that I&apos;ve crashed the production version of Chrome eight times.&lt;/p&gt;
&lt;p&gt;I am among the top non-Google people to file WebRTC issues. And I managed to get quite a few of them fixed, too. I visited Google&apos;s Stockholm office in September and had a conversation with the team there about how I use the issue tracker and how that process works. Full disclosure: I got a t-shirt (even though it turned out to be too large). And I even started reviewing the Chrome WebRTC release notes before they&apos;re sent out. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Justin Uberti&apos;s description of WebRTC as a &lt;a href=&quot;http://youtu.be/E8C8ouiXHHk?t=20s&quot;&gt;&quot;project to bring realtime communication to the open web platform&quot;&lt;/a&gt; is still the vision I cling to.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are some amazing people working on Google&apos;s WebRTC team and I like working with them.&lt;/p&gt;
&lt;p&gt;The same holds true for some of the Mozilla folks. &lt;/p&gt;
&lt;p&gt;One of the &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1000858&quot;&gt;first bugs I reported&lt;/a&gt; got fixed in less than 24 hours. I started to hang out regularly in the #media channel on the Mozilla IRC and got my bugs fixed even faster. Also, the Mozilla team is currently working on multistream support with the Jitsi team, which is going to be quite important for the next version of Talky as well. It is very good to see &quot;coming soon&quot; for both this and renegotiation on &lt;a href=&quot;https://twitter.com/OsloWebRTC/status/542347684536147968&quot;&gt;these slides&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But yesterday Mozilla CTO Andreas Gal wrote a blog post entitled &lt;a href=&quot;http://andreasgal.com/2014/12/09/it-takes-many-to-build-the-web-we-want/&quot;&gt;&quot;It takes many to build the Web we want.&quot;&lt;/a&gt; In describing the WebRTC Competency Center that Mozilla is starting with the help of telcos, he makes an interesting statement:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The goal of this new center is to implement WebRTC with a broad, neutral vision that captures the technology needs of many, not just the technology needs of individual browser vendors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are other points in the blog post I strongly disagree with, but let me pick on this one. Basically he accuses another browser vendor of only fulfilling its own technical needs. Since there is just one other browser vendor which does WebRTC currently, this must be aimed at Google and its Hangouts service.&lt;/p&gt;
&lt;p&gt;A while back, Google enabled &quot;WebRTC&quot; for Hangouts, which only works in Chrome. I wrote a quite lengthy technical &lt;a href=&quot;https://webrtchacks.com/hangout-analysis-philipp-hancke/&quot;&gt;explanation for webrtcHacks&lt;/a&gt; that explains why it only works with Chrome. Andreas Gal used the phrase &quot;the web we want&quot;  &lt;a href=&quot;https://twitter.com/andreasgal/status/486562683211100163&quot;&gt;in a tweet&lt;/a&gt; back then.&lt;/p&gt;
&lt;p&gt;I am very unhappy about this new statement. I do agree that Google ensured that Hangouts works with Chrome (see the webrtcHacks article). What annoys me about this statement is the accusation that Google does not care about &quot;the technology needs of many.&quot; This is absolutely not my experience working with Google&apos;s WebRTC team.&lt;/p&gt;
&lt;p&gt;Here&apos;s a particular example. TURN support is very integral for WebRTC, since it ensures connectivity between browsers in certain circumstances. Chrome now has excellent TURN support, even though it took quite a while (almost two years) to get there. I have filed a number of issues and they got fixed. Debugging those issues was not an easy task, and I am sure a lot of engineering time was spent by the WebRTC team at Google.&lt;/p&gt;
&lt;p&gt;When Hangouts was released, one thing surprised me: it does not use TURN. Instead, it uses ICE-TCP for falling back to port 443 on restricted networks. Which explains why those TURN bugs were not found earlier; Google simply did not use this in production. And yet, they fixed my bugs. Because supporting the broader WebRTC community is important to them—regardless of Hangouts.&lt;/p&gt;
&lt;p&gt;From our perspective, both the Chrome and Mozilla WebRTC dev teams have been great to work with. And they both care, as we do, about making realtime communication technologies friendly for web developers. So the comment from Andreas Gal about &quot;the web we want&quot; is a bit confusing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At &amp;#x26;yet, the web &lt;em&gt;we&lt;/em&gt; want applies &lt;a href=&quot;http://tantek.com/2010/281/b1/what-is-the-open-web&quot;&gt;open web principles&lt;/a&gt; to realtime communication. It&apos;s that simple.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We&apos;ll be exploring what that means more deeply in upcoming blog posts.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[hapi 8 is coming. Are you ready?]]></title><description><![CDATA[For those of you who don't know, hapi is a web framework with a rapidly growing community led by Eran Hammer.Over the last month, a lot of…]]></description><link>https://blog.andyet.com/2014/12/09/hapi-8/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/09/hapi-8/</guid><pubDate>Tue, 09 Dec 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For those of you who don&apos;t know, &lt;a href=&quot;http://hapijs.com&quot;&gt;hapi&lt;/a&gt; is a web framework with a rapidly growing community led by &lt;a href=&quot;http://twitter.com/eranhammer&quot;&gt;Eran Hammer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Over the last month, a &lt;em&gt;lot&lt;/em&gt; of work has gone into it to prepare for the release of version 8.0.0. hapi 8 represents the biggest release since the start of the framework, and with it come quite a few changes.&lt;/p&gt;
&lt;h2 id=&quot;no-more-packs&quot;&gt;&lt;a href=&quot;#no-more-packs&quot; aria-label=&quot;no more packs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;No more packs&lt;/h2&gt;
&lt;p&gt;That&apos;s right, those confusing pack things are gone. If you used them, though, don&apos;t worry. The functionality still exists, just in different ways. Instead of a pack that contains servers, we now have a server that contains connections. You can still create a server with multiple connections, but if you only need one; everything will feel much more straightforward and intuitive.&lt;/p&gt;
&lt;p&gt;If you&apos;re used to using &lt;code class=&quot;language-text&quot;&gt;Pack.compose&lt;/code&gt; you&apos;ll want to check out &lt;a href=&quot;https://github.com/hapijs/glue&quot;&gt;glue&lt;/a&gt;, which has taken over that functionality.&lt;/p&gt;
&lt;h2 id=&quot;promise-support&quot;&gt;&lt;a href=&quot;#promise-support&quot; aria-label=&quot;promise support permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Promise support&lt;/h2&gt;
&lt;p&gt;That&apos;s right folks, you asked for it and hapi listened. You can now &lt;code class=&quot;language-text&quot;&gt;reply()&lt;/code&gt; with a promise in handlers, as well as use them in server methods. hapi will resolve the promise and send the correct data for you.&lt;/p&gt;
&lt;h2 id=&quot;more-consistent-reply-interface&quot;&gt;&lt;a href=&quot;#more-consistent-reply-interface&quot; aria-label=&quot;more consistent reply interface permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More consistent reply interface&lt;/h2&gt;
&lt;p&gt;Gone is the distinction between &lt;code class=&quot;language-text&quot;&gt;next&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;reply&lt;/code&gt;. Instead, in the majority of places you&apos;ll receive the same &lt;code class=&quot;language-text&quot;&gt;reply&lt;/code&gt; interface as you do in request handlers.&lt;/p&gt;
&lt;p&gt;This does mean a few changes, however. If you want to pass control from a server extension back to the chain, call &lt;code class=&quot;language-text&quot;&gt;reply.continue()&lt;/code&gt; instead of an empty reply. Calling &lt;code class=&quot;language-text&quot;&gt;reply()&lt;/code&gt; as before will instead send an empty response, and that&apos;s probably not what you want.&lt;/p&gt;
&lt;h2 id=&quot;extensible-reply-interface&quot;&gt;&lt;a href=&quot;#extensible-reply-interface&quot; aria-label=&quot;extensible reply interface permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Extensible reply interface&lt;/h2&gt;
&lt;p&gt;Speaking of the &lt;code class=&quot;language-text&quot;&gt;reply&lt;/code&gt; interface, you can add your own methods to it now!&lt;/p&gt;
&lt;p&gt;Ever wanted a &lt;code class=&quot;language-text&quot;&gt;reply.success()&lt;/code&gt; method so you don&apos;t have to keep typing out &lt;code class=&quot;language-text&quot;&gt;reply({ status: &amp;#39;success&amp;#39; })&lt;/code&gt;? Well, now you can have it. In fact, you can attach any method you want to the &lt;code class=&quot;language-text&quot;&gt;reply&lt;/code&gt; interface and use it throughout your entire server.&lt;/p&gt;
&lt;h2 id=&quot;a-lot-of-stuff-got-deleted&quot;&gt;&lt;a href=&quot;#a-lot-of-stuff-got-deleted&quot; aria-label=&quot;a lot of stuff got deleted permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A lot of stuff got deleted&lt;/h2&gt;
&lt;p&gt;As part of the push for simplicity, a lot of useless and/or redundant functionality was removed. As I mentioned, packs are gone and the &lt;code class=&quot;language-text&quot;&gt;Pack.compose&lt;/code&gt; functionality has been moved to &lt;a href=&quot;https://github.com/hapijs/glue&quot;&gt;glue&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also removed is &lt;code class=&quot;language-text&quot;&gt;Hapi.error&lt;/code&gt;. If you were using it before you should update your code to use &lt;a href=&quot;https://github.com/hapijs/boom&quot;&gt;boom&lt;/a&gt; directly.&lt;/p&gt;
&lt;p&gt;The deprecated &lt;code class=&quot;language-text&quot;&gt;Hapi.createServer&lt;/code&gt; method has been removed completely, in favor of simply calling &lt;code class=&quot;language-text&quot;&gt;new Hapi.Server()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;Hapi.version&lt;/code&gt; has also been removed. If you need to know what version of hapi you&apos;re using, you should simply require hapi&apos;s &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; (which is easy to do, something like &lt;code class=&quot;language-text&quot;&gt;var hapiPkg = require(&amp;#39;hapi/package&amp;#39;);&lt;/code&gt; works nicely).&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;hapi&lt;/code&gt; CLI command has also been removed from the framework. If you were using it, check out the &lt;a href=&quot;https://github.com/hapijs/rejoice&quot;&gt;rejoice&lt;/a&gt; module for that functionality.&lt;/p&gt;
&lt;h2 id=&quot;lots-more&quot;&gt;&lt;a href=&quot;#lots-more&quot; aria-label=&quot;lots more permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lots more&lt;/h2&gt;
&lt;p&gt;These are just a few of the major changes that are coming. For a complete list, do yourself a favor and check out the &lt;a href=&quot;https://github.com/hapijs/hapi/issues/2186&quot;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;get-ready&quot;&gt;&lt;a href=&quot;#get-ready&quot; aria-label=&quot;get ready permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Get ready!&lt;/h2&gt;
&lt;p&gt;hapi 8.0.0 is set to be released this Thursday, December 11th. If you maintain a plugin, or you&apos;re using hapi for your projects, I strongly encourage you to take a look at updating.&lt;/p&gt;
&lt;p&gt;As mentioned in the &lt;a href=&quot;https://github.com/hapijs/hapi/issues/2254&quot;&gt;support schedule&lt;/a&gt; the last version of hapi before 8.0 that will receive any support at all is 7.5, which will only receive critical and security related updates, and only until March 4th of 2015.&lt;/p&gt;
&lt;p&gt;Don&apos;t drag your feet, start updating as soon as you can!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[I can writing and so are you]]></title><description><![CDATA[As a semi-official part of the &yet Blog Team and a super-official, semi-professional antagonizer, I spend a lot of time kicking in office…]]></description><link>https://blog.andyet.com/2014/12/08/i-can-writing/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/08/i-can-writing/</guid><pubDate>Mon, 08 Dec 2014 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As a semi-official part of the &lt;a href=&quot;http://blog.andyet.com/&quot;&gt;&amp;#x26;yet Blog&lt;/a&gt; Team and a super-official, semi-professional antagonizer, I spend a lot of time kicking in office doors and demanding that people write things. Some of those folks (once they’ve come to the realization that I will not stop making this pose in their doorframe) &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mikespeegle.files.wordpress.com/2014/11/minispeegle.png&quot; alt=&quot;DO THEM&quot;&gt;&lt;/p&gt;
&lt;p&gt;…will buckle down and whip out some words about JavaScript or Node or NodeScript or JavaNode  or BackBonemBerGular or whatever in a jiffy, and if only to dislodge my presence from their immediate vicinity for one more day. Others flatly refuse, and that&apos;s okay too. &lt;/p&gt;
&lt;p&gt;But there are others. &lt;/p&gt;
&lt;h3 id=&quot;enter-the-thirdies&quot;&gt;&lt;a href=&quot;#enter-the-thirdies&quot; aria-label=&quot;enter the thirdies permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Enter the Thirdies&lt;/h3&gt;
&lt;p&gt;There are a few folks, however, who inhabit a shadowy third group–a group that lies in the shaded penumbra between Does Write and Doesn’t. These few (and here I shall call them “thirdies,” if only because I like to assign monikers wherever possible) don’t actually NOT want to write, but are paralyzed by concerns regarding quality, length, grammar, diction, syntax, appropriateness of context, authorial voice, tenseness regarding tense changes, Fear of the Blank Page, surprise narcolepsy, and a whole, variegated rainbow of school-age phobias including but not limited to dangling participles, oxford commas, i before e except after c rules and, of course, the proper use of the word “peruse.”&lt;/p&gt;
&lt;p&gt;Which is all bullshit, by the way. &lt;/p&gt;
&lt;p&gt;“But why, Mike? Why do you say such things when I clearly am just not very good at writing, and am thus afraid that everyone is going to laugh at me, as suggested by &lt;a href=&quot;http://www.imdb.com/name/nm0001453/&quot;&gt;Piper Laurie&lt;/a&gt; in the 1976 horror classic, &lt;a href=&quot;http://www.imdb.com/title/tt0074285/?ref_=nm_flmg_act_75&quot;&gt;Carrie&lt;/a&gt;?”&lt;/p&gt;
&lt;p&gt;Listen. Hey. You’re looking at this all wrong. &lt;/p&gt;
&lt;h3 id=&quot;because&quot;&gt;&lt;a href=&quot;#because&quot; aria-label=&quot;because permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Because:&lt;/h3&gt;
&lt;p&gt;When capital-W Writers write, they all claim to have a process. Some, like Stephen “pig blood and telekinesis” King writes with the door closed until the second draft. &lt;a href=&quot;http://www.nickharkaway.com/&quot;&gt;Nick “quite possibly Mike’s best friend but doesn’t quite know it yet” Harkaway&lt;/a&gt; writes with the door open. Me? I have &lt;a href=&quot;http://blog.andyet.com/2014/10/31/Pitching-the-Novel&quot;&gt;my own prose process&lt;/a&gt; (although to be fair, &lt;a href=&quot;http://blog.andyet.com/2014/11/03/Pen-Paper-Punk-Rock-Productivity&quot;&gt;some folks&lt;/a&gt; have their very own, kickass writing ways &apos;round here). &lt;/p&gt;
&lt;p&gt;In short: the process is insane–and for anyone short of those lucky (very) few–a fool’s errand (Luckily I am just such a fool! Ha ha!). You have to either really REALLY want to do it, or be utterly immune to CRUSHING DISAPPOINTMENT. &lt;/p&gt;
&lt;p&gt;But the problem there (other than my whiskey bill), is that the process and the people involved in it have thrown up this whole wall of mystique around the whole writing thing, and have thus turned the process by which thoughts become words into something that can seem very scary from the outside. &lt;/p&gt;
&lt;p&gt;So. &lt;/p&gt;
&lt;h3 id=&quot;lets-try-something-different-in-five-easy-steps&quot;&gt;&lt;a href=&quot;#lets-try-something-different-in-five-easy-steps&quot; aria-label=&quot;lets try something different in five easy steps permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let&apos;s try something different (in five easy steps).&lt;/h3&gt;
&lt;h4 id=&quot;step-one-speak-a-language&quot;&gt;&lt;a href=&quot;#step-one-speak-a-language&quot; aria-label=&quot;step one speak a language permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step One: Speak a language.&lt;/h4&gt;
&lt;p&gt;Odds are you already do this. Can you communicate with words in such a way that another human (or failing that, macaw and/or parrot) can understand you? Can you regularly convey ideas without having to resort to flash cards with groceries and stuff drawn on them? Then you already have the toolbox for writing prose. &lt;/p&gt;
&lt;h4 id=&quot;step-two-write-like-you&quot;&gt;&lt;a href=&quot;#step-two-write-like-you&quot; aria-label=&quot;step two write like you permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step Two: Write like YOU.&lt;/h4&gt;
&lt;p&gt;Seriously. Just write like you talk. This is the internet age. The old ways are dying slowly. Folks use “ain’t” and “gonna” and “wtf” in common speech pretty much all the time these days. And if you use those things in spoken speech and then commit them to the page, then your writing is going to seem genuine and awesome. But if you try to write in such a way that impresses your 8th grade English teacher, then it’s going to suck. So don’t throw a bunch of em dashes and semicolons in there if you’re not comfortable with them; simplicity is always better in a pinch. &lt;/p&gt;
&lt;h4 id=&quot;step-three-be-passionate-about-something-and-dont-be-afraid-to-admit-it&quot;&gt;&lt;a href=&quot;#step-three-be-passionate-about-something-and-dont-be-afraid-to-admit-it&quot; aria-label=&quot;step three be passionate about something and dont be afraid to admit it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step Three: Be passionate about something (and don’t be afraid to admit it).&lt;/h4&gt;
&lt;p&gt;Like most of the thirdies I know, you probably like something. In fact, I am willing to bet that you’re crazy passionate about something. But for some reason, a lot of thirdies feel a degree of trepidation when it comes to sharing what they love. But passion–like your true voice in Step Two–shines through and makes any piece of writing more valuable than the sum of its parts. What’s more, there are probably plenty of other people out there who have the same passions you do, but who have a similar problem communicating, and thus feel isolated and weird because of it. So go on and share! This is the internet after all. &lt;/p&gt;
&lt;h4 id=&quot;step-four-use-the-tools&quot;&gt;&lt;a href=&quot;#step-four-use-the-tools&quot; aria-label=&quot;step four use the tools permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step Four: Use the tools.&lt;/h4&gt;
&lt;p&gt;Writing is so much easier than it has ever been before. Seriously. Just try and misspell a word in Pages. It is so very difficult. Do you know what a pain in the ass it was to use a made up word like “thirdies” over and over again without adding it to the dictionary? A huge one is what. &lt;/p&gt;
&lt;p&gt;And although it will make some purists out there apoplectic with blind, frothing rage, you should lean on the crazy ubiquitous tools out there to improve your writing. Use spell check. Use thesaurus.com. Phone a friend. Go to Grammar Girl and learn the difference between “affect” and “effect.” Basically, use a scintilla of that passion that you feel for X and apply an iota of it to research. &lt;/p&gt;
&lt;h4 id=&quot;step-five-try-seriously-just-try&quot;&gt;&lt;a href=&quot;#step-five-try-seriously-just-try&quot; aria-label=&quot;step five try seriously just try permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Step Five: Try. Seriously. Just try.&lt;/h4&gt;
&lt;p&gt;Okay. Like the man said, “&lt;a href=&quot;http://starwars.wikia.com/wiki/Yoda&quot;&gt;do or do not&lt;/a&gt;” etc. Because dig this if you will: the first thing you write may be total crap. It may be the most terrible dreck that ever crawled ‘cross the page. It may be an affront to &lt;a href=&quot;https://www.google.com/webhp?sourceid=chrome-instant&amp;#x26;ion=1&amp;#x26;espv=2&amp;#x26;ie=UTF-8#q=ernest%20hemingway&quot;&gt;the&lt;/a&gt; &lt;a href=&quot;https://www.google.com/webhp?sourceid=chrome-instant&amp;#x26;ion=1&amp;#x26;espv=2&amp;#x26;ie=UTF-8#q=jane%20austen&quot;&gt;literary&lt;/a&gt; &lt;a href=&quot;https://www.google.com/webhp?sourceid=chrome-instant&amp;#x26;ion=1&amp;#x26;espv=2&amp;#x26;ie=UTF-8#q=mark%20twain&quot;&gt;gods&lt;/a&gt; in their &lt;a href=&quot;https://www.google.com/webhp?sourceid=chrome-instant&amp;#x26;ion=1&amp;#x26;espv=2&amp;#x26;ie=UTF-8#q=library+of+alexandria&quot;&gt;book-smelling pantheon above&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;But guess what: at least it’s something. &lt;/p&gt;
&lt;p&gt;As a sometime editor, I can always massage grammar and syntax. I can fix tense changes and add capitalization where need be. Hell, in extreme circumstances, I can sit right down by you and talk you through the process of concrete-detail-supporting-argument-supporting-argument. &lt;/p&gt;
&lt;p&gt;But I can’t. &lt;/p&gt;
&lt;p&gt;Fix. &lt;/p&gt;
&lt;p&gt;Nothing. &lt;/p&gt;
&lt;p&gt;If you don’t write, you don’t get better. You WON’T get better. And the sad part will be that your not-getting-better-ness won’t be from lack of talent, but from lack of trying. &lt;/p&gt;
&lt;p&gt;And that is the saddest thing of all. &lt;/p&gt;
&lt;h3 id=&quot;the-whole-point-for-the-tldr-crowd&quot;&gt;&lt;a href=&quot;#the-whole-point-for-the-tldr-crowd&quot; aria-label=&quot;the whole point for the tldr crowd permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The whole point (for the TL;DR crowd).&lt;/h3&gt;
&lt;p&gt;Some people can write and do. Which is fine. Some people can write and don’t. Also fine. &lt;/p&gt;
&lt;p&gt;But some people (quite possibly like YOU) CAN write and maybe SHOULD write but don’t because of fear. &lt;/p&gt;
&lt;p&gt;But seriously, screw fear. &lt;/p&gt;
&lt;p&gt;You don’t need to write like me or like Stephen King or like Neil Gaiman or like Mrs. Frizzle or whomever. &lt;/p&gt;
&lt;p&gt;Just write like you. &lt;/p&gt;
&lt;p&gt;And maybe it will turn out great. &lt;/p&gt;
&lt;p&gt;(P.S. and have that damn blog entry on my desk by 8 am tomorrow or SO HELP ME GOD. -M)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The point of building software, together]]></title><description><![CDATA[Despite how we mostly share what we've learned about making great software, software really isn't the point of what we do at &yet. Writing…]]></description><link>https://blog.andyet.com/2014/12/05/and-you/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/05/and-you/</guid><pubDate>Fri, 05 Dec 2014 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Despite how we mostly share what we&apos;ve learned about making great software, &lt;strong&gt;software really isn&apos;t the point of what we do at &amp;#x26;yet.&lt;/strong&gt; Writing code and designing interfaces and helping build software products and teaching what we know is all just an excuse to spend time on what we really care about – which is people.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Getting to be with our favorite people while we figure out challenging, interesting problems together is the whole point.&lt;/strong&gt; If we were good at building ocean liners, that&apos;s what we&apos;d be doing. It just happens that we&apos;re good at building software.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Last month, we started sending out a bi-weekly dispatch that we&apos;re calling &amp;#x26;you.&lt;/strong&gt; Close to 4,000 of you are signed up, and we&apos;re really grateful for the conversations we&apos;ve been having with many of you.&lt;/p&gt;
&lt;p&gt;So far, we&apos;ve shared stories about what&apos;s on our minds these days, asked questions about what you&apos;re doing, spotlighted people in the &amp;#x26;you community and their projects, and shared some of our favorite reads and resources.&lt;/p&gt;
&lt;p&gt;Coming up, we&apos;re creating a twitter list so we can all find each other in one place, plus we&apos;re making a special (still free) version of Talky just for the &amp;#x26;you community to use before the new public version comes out, and we&apos;re thinking of more crazy impossible things we can do together.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We&apos;re not really sure where we&apos;ll end up.&lt;/strong&gt; But we do know one thing: if we&apos;re doing it together, that&apos;s pretty much all we need.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Tao of Ops: Dealing with disappearing DNS]]></title><description><![CDATA[You're looking at your todo list and pondering what code to write during one of the brief moments of free time that appear on your daily…]]></description><link>https://blog.andyet.com/2014/12/03/redundant-dns/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/03/redundant-dns/</guid><pubDate>Wed, 03 Dec 2014 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You&apos;re looking at your todo list and pondering what code to write during one of the brief moments of free time that appear on your daily schedule, when all of the sudden you get a message in team chat: Is the site down for anyone else? &lt;/p&gt;
&lt;p&gt;It can be a frustrating experience, but never fear; you&apos;re not alone. We here at &amp;#x26;yet experienced this type of outage once before, and then again this week. In fact, nearly every operations team has experienced at least a variation on the above nightmare. It is just a matter of time before you have to deal with people thinking your site or service is down when the problem is really with the Domain Name Service (DNS). Even shops that spend a lot of money to work with DNS vendors who themselves have some serious redundancy and scale will eventually fall prey to an orchestrated &lt;a href=&quot;https://blog.andyet.com/2014/02/24/what-exactly-is-a-ddos&quot;&gt;Distributed Denial of Service Attack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So what did we learn when we were faced with an attack this week? Mainly, a reminder of the importance of redundancy. The best solution is still the simplest: have more than one DNS vendor. Now don&apos;t be fooled by the use of the word &quot;simple&quot; - while redundancy is the simplest, it is not a simple process to implement at all, but let&apos;s walk through what we will need.&lt;/p&gt;
&lt;p&gt;Pick the two (or more) vendors. The crucial part for this is that both vendors have to have an API for changes to your DNS Zone records. If they don&apos;t have an API, you will be forced to make updates using their web interface and that just is not a recipe for success at all! Another criterion is that both vendors should have solid track records with dealing with DDoS events - no use picking a vendor that falls over at the slightest attack.&lt;/p&gt;
&lt;p&gt;Once you have two vendors selected, the next step is to gather the tools to coordinate zone record changes with each vendor. One thing to watch out for is that any given tool is able to both create new entries and also adjust/change existing entries (each API has its own quirks to deal with, so do your homework). This can be a command line tool that they provide or that your configuration/change management tool supports, but most likely it will be a small set of scripts that you create to take the structured DNS data (JSON, XML, CSV, whatever is good for your team) and push the new/changed items to each vendor&apos;s API. A good example of one of these tools is what the Netflix team uses - &lt;a href=&quot;http://techblog.netflix.com/2013/03/denominator-multi-vendor-interface-for.html&quot;&gt;denominator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The last step is to adjust the nameserver list for each domain to contain entries from both vendors. This will allow for fallback lookups to happen if a DNS client request cannot be solved because the primary nameserver could not be reached.&lt;/p&gt;
&lt;p&gt;With the above in place you will be able to continue on the Operations Path without having to fend off the zombie DDoS horde - always a good thing for you and your team.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The ending is the hardest part]]></title><description><![CDATA[This is how I've felt about every project I've ever done.StartingStarting a project is fun. There's infinite possibility. There's no…]]></description><link>https://blog.andyet.com/2014/12/01/the-end/</link><guid isPermaLink="false">https://blog.andyet.com/2014/12/01/the-end/</guid><pubDate>Mon, 01 Dec 2014 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is how I&apos;ve felt about every project I&apos;ve ever done.&lt;/p&gt;
&lt;h3 id=&quot;starting&quot;&gt;&lt;a href=&quot;#starting&quot; aria-label=&quot;starting permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Starting&lt;/h3&gt;
&lt;p&gt;Starting a project is fun. There&apos;s infinite possibility. There&apos;s no pressure. You haven&apos;t messed it all up yet.&lt;/p&gt;
&lt;h3 id=&quot;middle&quot;&gt;&lt;a href=&quot;#middle&quot; aria-label=&quot;middle permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Middle&lt;/h3&gt;
&lt;p&gt;The middle of a project is pretty good, too. The boilerplate stuff is done. There are still some hard little nuggets of problems to work on and find creative solutions to. Some bits are starting to get polished, which is fun. There&apos;s no pressure to finish yet.&lt;/p&gt;
&lt;h3 id=&quot;end&quot;&gt;&lt;a href=&quot;#end&quot; aria-label=&quot;end permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;End&lt;/h3&gt;
&lt;p&gt;The end is a nightmare. The pressure (internal or external) to ship it increases. There&apos;s still a lot to do, and a lot of tiny odds and ends, which are really hard to focus on. There are often still some big questions or pieces of work, that may or may not need to be fixed before it ships; but there&apos;s no way to be sure. &lt;/p&gt;
&lt;p&gt;The reckoning is coming: one day this thing will ship; and it will be a reflection of everything you&apos;ve done. It&apos;s the opportunity for people to find out that it&apos;s not very good; and you, as the developer, have no excuses left. At the start and the middle you can fix stuff &quot;later.&quot; At the end, if it&apos;s not done, it&apos;s not done. And maybe you&apos;re done? &lt;/p&gt;
&lt;p&gt;Daily productivity crawls too. Going from 0 lines of code to 1000 is a blaze of new functionality and apparent productivity. Who, apart from you, knows what changes when you go from 5000 -&gt; 6000 lines of code?&lt;/p&gt;
&lt;p&gt;If the start is the infinite possibility of things you can do, the end is an infinite list of things you didn&apos;t do.&lt;/p&gt;
&lt;p&gt;Just getting &quot;done&quot; is hard too. The &lt;a href=&quot;https://trello.com/&quot;&gt;Trello&lt;/a&gt; board becomes overwhelming with tiny bugs and huge issues and things you have no intention of fixing but are still there for who knows why? There&apos;s so much to do, and so little time. How do you know what to work on? Everything in isolation seems insignificant compared to the full list of other things, so as soon as you try and work on one, everything else seems more important. &lt;/p&gt;
&lt;p&gt;How do you even figure out what the most important thing is to work on?&lt;/p&gt;
&lt;p&gt;Towards the end - every new bud of an idea on something that&apos;s not your main project is a tempting distraction. An idea someone has for something. An idea you have for something. A bug or support request someone has in an open source project of yours, or someone else&apos;s. These are all opportunities to show yourself, and everyone else, that you aren&apos;t a total screwup. What better way to deal with the slow productivity you&apos;re making on project X, when you can make those amazing gains on a, b and c? It&apos;s a fallacy of course. But it&apos;s a real feeling.&lt;/p&gt;
&lt;h3 id=&quot;so-how-do-we-make-it-better&quot;&gt;&lt;a href=&quot;#so-how-do-we-make-it-better&quot; aria-label=&quot;so how do we make it better permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So how do we make it better?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Communicate, communicate...&lt;/strong&gt;
Being really clear with coworkers that your main project right now is X, and it&apos;s in a really tough phase. And to politely ask that they avoid distracting you with new temptations that aren&apos;t critical, and perhaps more importantly, to encourage them to try and guide you away from starting new things that will distract you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;...and then communicate some more.&lt;/strong&gt;
Having open and honest dialog with colleagues about the state of the project; to be really clear with them about what needs to be done and what doesn&apos;t. And to get their assurances that even though the productivity towards the end feels slow, they understand and aren&apos;t going to be standing there wondering what the heck you are doing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Break it down.&lt;/strong&gt;
Figuring out how to keep on top of that Trello board/issue list/whatever, so that it doesn&apos;t become a distracting list of things that are never going to get done. How can you break down big tasks, or group little bug fixes which are too small, in order to keep the list size down?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Recognise that it won&apos;t all be done in a day.&lt;/strong&gt;
One of my pervasive flaws is looking at the list of things, and thinking &quot;Argghh why isn&apos;t this done yet, I need to get this all done today.&quot; Which is, of course, totally ridiculous thinking that leads to panic mode. To overcome this challenge, I&apos;m working to get better at actually sitting down and planning out the list of things to do over the course of the iteration so that incremental progress on a daily basis feels like good progress. &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;and-you&quot;&gt;&lt;a href=&quot;#and-you&quot; aria-label=&quot;and you permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;And you?&lt;/h3&gt;
&lt;p&gt;After sharing this with a few other developers I know, it quickly became clear that I&apos;m not the only one who fights with these feelings on software projects. This was a relief to hear, though sadly nobody&apos;s handed me a magic bullet yet either. If you have stories, thoughts, or ideas you&apos;d like to share, let me know on &lt;a href=&quot;http://twitter.com/philip_roberts&quot;&gt;twitter&lt;/a&gt; -- I&apos;d love to hear them.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Turkeys]]></title><description><![CDATA[a turkey wearing headphones listening to a phonograph, the music is probably dubstepSix years ago, around this time of year, I met this…]]></description><link>https://blog.andyet.com/2014/11/26/turkeys/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/26/turkeys/</guid><pubDate>Wed, 26 Nov 2014 18:56:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://cldup.com/95QNILiE6J-2000x2000.png&quot; alt=&quot;a turkey wearing headphones listening to a phonograph, the music is probably dubstep&quot;&gt;&lt;/p&gt;
&lt;p&gt;Six years ago, around this time of year, I met this turkey for the first time.&lt;/p&gt;
&lt;p&gt;It was on a flyer for a little local music venue called The Red Room that had received quite a bit of acclaim. I&apos;d heard of the venue, but hadn&apos;t been there yet. I hadn&apos;t met anyone who&apos;d been to it yet, so somehow it wasn&apos;t really &lt;em&gt;real&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The flyer sat on the counter of a tiny print shop on the far side of Pasco. I say &quot;shop,&quot; but this was a warehouse. I could hear the giant analog four-color press churning out Spanish-language phone books, going &quot;chkunk-shhhh-chkunk-shhhh-chkunk!&quot; faster than I could possibly onomatopoeticate.&lt;/p&gt;
&lt;p&gt;I had shown up to print the first brochure for a little business I&apos;d started haphazardly. &lt;/p&gt;
&lt;p&gt;The brochure was in RGB color—&lt;em&gt;gasp!&lt;/em&gt;—and not print standard CMYK. I&apos;m glad I didn&apos;t tie my personal pride to my print design because this was apparently like showing up to a hockey game with figure skates (but I don&apos;t know anything about hockey either though, so...).&lt;/p&gt;
&lt;p&gt;I stood awkwardly at the counter while the very friendly young woman swiped and clicked away at the iMac across the room, recoloring my entire brochure for free.&lt;/p&gt;
&lt;p&gt;I held up the flyer with the turkey on it. &quot;Have you ever been to this place?&quot; I asked her.&lt;/p&gt;
&lt;p&gt;&quot;Oh yeah. I help run it! :)&quot; Apparently the only person in the world who speaks with audible smileyface emoticons.&lt;/p&gt;
&lt;p&gt;&quot;These flyers are really cool. Who did the design and artwork for them?&quot; I asked.&lt;/p&gt;
&lt;p&gt;&quot;Oh! Thanks! I did! :)&quot; &lt;a href=&quot;http://andyet.com/team/amy&quot;&gt;Amy&lt;/a&gt; said.&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;&quot;Do you know Python? Do you know anyone locally who does?&quot; I DM&apos;d to &lt;a href=&quot;http://twitter.com/thebrianmanley&quot;&gt;Brian Manley&lt;/a&gt;, one of the few local nerds I knew on Twitter in 2008.&lt;/p&gt;
&lt;p&gt;&quot;Nope. &lt;a href=&quot;http://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; does,&quot; came the reply.&lt;/p&gt;
&lt;p&gt;After years writing PHP and hacking things together with jQuery, I decided I wanted to get into more development. I&apos;d been doing a few small projects with Rails, and I was intrigued by Django. But I needed a Python primer and someone I could ask when I got snowed in by a stacktrace.&lt;/p&gt;
&lt;p&gt;I reached out to &lt;a href=&quot;http://andyet.com/team/fritzy&quot;&gt;Fritzy&lt;/a&gt;, and soon realized I knew him from junior high. &lt;/p&gt;
&lt;p&gt;I hung out with him for a bit, got some good pointers. I met his wife, Athena, and his cute kids: a very talkative and adorable Sam and a tiny Eileen.&lt;/p&gt;
&lt;p&gt;Fritzy told me he had a minuscule office and extra space to rent. It was 10&apos; by 12&apos; but I was happy to squeeze in among Nathan and an intimidating man who went by the name &quot;&lt;a href=&quot;http://andyet.com/team/gar&quot;&gt;Gar&lt;/a&gt;.&quot;&lt;/p&gt;
&lt;p&gt;Not long after, I got the most random email ever from some security guy who was a friend of theirs. Apparently my contact form CAPTCHA was insecure. I didn&apos;t really care about that, but until that moment, I had never thought about security.&lt;/p&gt;
&lt;p&gt;A couple days later, this random guy shows up in the office while I&apos;m alone and startles me half to death. &quot;Hahahaha,&quot; he laughed at my sheet-white expression. &quot;I&apos;m &lt;a href=&quot;http://andyet.com/team/baldwin&quot;&gt;Adam&lt;/a&gt;—I&apos;m the guy who sent you the email about your contact form.&quot; &lt;/p&gt;
&lt;p&gt;Figures it&apos;d be the security guy scaring the crap out of me.&lt;/p&gt;
&lt;p&gt;Time passed and I got an IM out of the blue. &quot;I have this crazy idea,&quot; said Fritzy&apos;s IM avatar. &quot;What if you hired me and &amp;#x26;yet became a software company?&quot;&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;&quot;Hey! I just saw you&apos;re from the Tri-Cities. I&apos;m going to be up there in a couple weeks.&quot; &lt;/p&gt;
&lt;p&gt;Out of nowhere came an unexpectedly friendly DM from this very serious looking (German?) guy who had randomly followed me at some point. All I knew was he did Django and had a weird name. (&quot;Hendrick&quot;? Is that Swiss? And why does he look so intense?)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cldup.com/0K9_kztXBj-2000x2000.png&quot; alt=&quot;a really really really good looking picture of henrik&quot;&gt;&lt;/p&gt;
&lt;p&gt;We talked for a bit and decided to get Thai food when he was in town.&lt;/p&gt;
&lt;p&gt;That conversation went surprisingly great—especially given that he had only followed me by chance and it was by even &lt;em&gt;greater&lt;/em&gt; chance he DM&apos;d me (he &lt;a href=&quot;http://joreteg.com/post/652109637/twitter-is-useless-unless-you-want-your-dream-job&quot;&gt;was about to &lt;em&gt;unfollow&lt;/em&gt; me&lt;/a&gt; because he thought I was super weird on Twitter, but when he clicked my profile, he realized he was going to be in my area, so he DM&apos;d me instead).&lt;/p&gt;
&lt;p&gt;We talked for almost two hours about all kinds of things. It became clear we shared a lot of the same perspective on business, tech, and valuing people.&lt;/p&gt;
&lt;p&gt;The whole time, I sat there thinking, &quot;I really wish this &lt;a href=&quot;http://andyet.com/team/henrik&quot;&gt;Henrik&lt;/a&gt; guy lived up here and I got to work with him.&quot; And then I thought, &quot;How the hell do you say his last name again?&quot;&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;I could go on.&lt;/p&gt;
&lt;p&gt;I could tell you about the first sushi lunch I had with &lt;a href=&quot;http://andyet.com/team/eric&quot;&gt;Eric&lt;/a&gt;, or Thai with a contemplative &lt;a href=&quot;https://andyet.com/team/steph&quot;&gt;Stephanie&lt;/a&gt; asking, &quot;should I expect more meaning out of my job?&quot; or the magic of meeting &lt;a href=&quot;http://andyet.com/team/luke&quot;&gt;Luke&lt;/a&gt; because of &lt;a href=&quot;http://andyet.com/team/lynn&quot;&gt;Lynn&lt;/a&gt; and Lynn because of Luke. &lt;/p&gt;
&lt;p&gt;I could talk about getting introduced to &lt;a href=&quot;http://andyet.com/team/karolina&quot;&gt;Karolina&lt;/a&gt; by &lt;a href=&quot;http://twitter.com/janl&quot;&gt;Jan&lt;/a&gt;, of &lt;a href=&quot;http://andyet.com/team/jenn&quot;&gt;Jenn&apos;s&lt;/a&gt; certain destiny to be part of our team, the serendipity of a week spent with &lt;a href=&quot;http://andyet.com/team/jaime&quot;&gt;Jaime&lt;/a&gt;, or how the only reason I know &lt;a href=&quot;http://andyet.com/team/mike&quot;&gt;Mike&lt;/a&gt; is because he asked a group I was in to watch his stuff while he used the restroom at a coffee shop. Or how the only reason &lt;a href=&quot;http://andyet.com/team/ljon&quot;&gt;Ljon&lt;/a&gt; works here is because I was looking to meet a chef.&lt;/p&gt;
&lt;p&gt;On and on I could go, indeed.&lt;/p&gt;
&lt;p&gt;These are &lt;em&gt;just stories&lt;/em&gt; to most of you. &lt;/p&gt;
&lt;p&gt;But they all make me well up with gratitude when I look back on them.&lt;/p&gt;
&lt;p&gt;Who was I to come along the paths of these remarkable, wonderful people who would shape my life so profoundly? People who would teach me my own value, and help me learn what it is to be part of a team.&lt;/p&gt;
&lt;p&gt;Even if &amp;#x26;yet was shuttered and gone tomorrow, these people have marked me so deeply, I&apos;d still have to spend the rest of my life to express the gratitude I feel for them.&lt;/p&gt;
&lt;p&gt;How many people do we cross in our lives without thinking of how much of an impact they will have on us? How many people have had a tremendous impact on our lives and we never take the time to tell them? How few do we take the time to cherish and share that gratitude with?&lt;/p&gt;
&lt;p&gt;I will never cease being grateful for the many chance encounters I&apos;ve had that have led me to today. Through seasons of heartache and joy, I&apos;m grateful for every single person I have ever worked with and I will continue to be.&lt;/p&gt;
&lt;p&gt;I am a lucky bastard—Thanksgiving is my favorite holiday.&lt;/p&gt;
&lt;p&gt;Yes. These are &lt;em&gt;just stories.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But &lt;em&gt;you&lt;/em&gt; have your own stories.&lt;/p&gt;
&lt;p&gt;Stop today. Look around at the people in your life and remember how they got there.&lt;/p&gt;
&lt;p&gt;Whether we have everything or we have nothing, we always have the people in our lives.&lt;/p&gt;
&lt;p&gt;I hope that, when you do, your spirit wells up with gratitude for these people—and perhaps for the emails, CAPCHTAS, DMs, and maybe even serendipitous turkeys that brought you together.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;3&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Tao of Ops: Testing web forms]]></title><description><![CDATA[It's one thing to have a web application in production that requires active monitoring (you are monitoring it right?), but it's another…]]></description><link>https://blog.andyet.com/2014/11/26/tao-testing-web-forms/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/26/tao-testing-web-forms/</guid><pubDate>Wed, 26 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It&apos;s one thing to have a web application in production that requires active monitoring (&lt;a href=&quot;http://blog.andyet.com/2014/11/05/test-it-or-dont-trust-it&quot;&gt;you are monitoring it right?&lt;/a&gt;), but it&apos;s another issue completely when that web application contains a &quot;contact us&quot; form. All good teams will use various tools to gather emails so they can manage their subscriber lists appropriately, and that&apos;s the rub; what happens when code changes in the app that impacts the form? &lt;/p&gt;
&lt;p&gt;Nothing – why? Because you will be blissfully unaware your form is failing unless you test it.&lt;/p&gt;
&lt;p&gt;Testing a web form is what we are going to demonstrate using &lt;code class=&quot;language-text&quot;&gt;Python&lt;/code&gt; and the &lt;a href=&quot;https://pypi.python.org/pypi/mechanize/&quot;&gt;Mechanize&lt;/a&gt; library. Mechanize allows you to load a page, inspect any forms on the page and then manipulate the form just as a user would.&lt;/p&gt;
&lt;p&gt;Let&apos;s see some code!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; mechanize

br &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mechanize&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Browser&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
r  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; br&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;http://example.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Unable to load the test page&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    sys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exit&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# if your devs are nice and name the form...&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#     br.select_form(&quot;name&quot;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# if they don&apos;t name it, then you have to use...&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#     br.form = list(br.forms())[0]&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# To discover what the control field names are...&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#     for control in br.form.controls:&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;#         print(control.type, control.name)&lt;/span&gt;
br&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;form    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;br&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;forms&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
nameField  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; br&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;find_control&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
emailField &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; br&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;find_control&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
nameField&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Testing Form&quot;&lt;/span&gt;
emailField&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tester@example.com&quot;&lt;/span&gt;

r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; br&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;submit&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Error submitting form&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    sys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exit&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&apos;s it! With about a dozen lines of code we can now feel comfortable that any new work that the dev team does as they walk their path is being actively tested.&lt;/p&gt;
&lt;p&gt;For any team walking the Operations Path, more code would need to be added to this in order to make it production ready. The type of each input control could be checked and you could also add a range of values to test on submission.&lt;/p&gt;
&lt;p&gt;This small example can also be extended to test other aspects of your web application: link health, user agent response, device response. Each of these, and others, will be getting further attention in upcoming articles.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[An introduction to Ampersand.js (JS.LA)]]></title><description><![CDATA[Last month at JS.LA, Internet "Luke" Karrys gave a great introduction to Ampersand.js.Ampersand.js is a highly modular, loosely coupled, non…]]></description><link>https://blog.andyet.com/2014/11/25/luke-karrys-introduces-ampersand-at-js.la/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/25/luke-karrys-introduces-ampersand-at-js.la/</guid><pubDate>Tue, 25 Nov 2014 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Last month at &lt;a href=&quot;http://js.la&quot;&gt;JS.LA&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/lukekarrys&quot;&gt;Internet &quot;Luke&quot; Karrys&lt;/a&gt; gave a great introduction to &lt;a href=&quot;http://ampersandjs.com&quot;&gt;Ampersand.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ampersand.js is a highly modular, loosely coupled, non-frameworky framework for building advanced JavaScript apps.&lt;/p&gt;
&lt;p&gt;We&apos;ll let Luke explain:&lt;/p&gt;
&lt;iframe src=&quot;//player.vimeo.com/video/111015781&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt; &lt;p&gt;&lt;a href=&quot;http://vimeo.com/111015781&quot;&gt;Ampersand.js: The Non-Frameworky Framework&lt;/a&gt; from &lt;a href=&quot;http://vimeo.com/jsla&quot;&gt;JS.LA&lt;/a&gt; on &lt;a href=&quot;https://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;That was awesome. Way to go, Luke! If you want updates on more awesome stuff like Ampersand.js, why not sign up for our mailing list? Details below.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Hello there VP9. We've been waiting for you (but you're already making trouble).]]></title><description><![CDATA[Last week, Google Chrome started to support the next generation video codec VP9 for WebRTC (which is highly experimental in the developer…]]></description><link>https://blog.andyet.com/2014/11/24/hello-there-vp9/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/24/hello-there-vp9/</guid><pubDate>Mon, 24 Nov 2014 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Last week, Google Chrome &lt;a href=&quot;https://plus.google.com/+WebRTCorg/posts/3FLF2H7G9Ah&quot;&gt;started to support&lt;/a&gt; the next generation video codec VP9 for WebRTC (which is highly experimental in the developer version and you need to enable it, so the ETA for this is probably going to be mid-2015). That is good news because VP9 is going to offer better video quality at the same bandwidth (another way to look at it is that VP9 gives you the same quality at lower bandwidth, although at the expense of computational power, i.e. your mobile device gets warmer).&lt;/p&gt;
&lt;p&gt;I immediately wanted to implement and test the feature, if only so I could add Chrome 41 to the long list of versions that I managed to crash. However, this turned out to be harder than it initially seemed. &lt;/p&gt;
&lt;p&gt;Let me try to explain the issue with an example of a videochat that has three participants, two of which support VP9: Suppose that those clients use an XMPP MUC for having the conference, supported by an SFU like the Jitsi videobridge (which is what we do in the next version of Talky). The browsers announce their capabilities (&quot;I implement VP8,&quot; &quot;I implement VP9,&quot; a Firefox browser might even do H.264 and VP8) through &lt;a href=&quot;http://www.xmpp.org/extensions/xep-0115.html&quot;&gt;Entity Capabilites&lt;/a&gt; when joining the MUC. &lt;/p&gt;
&lt;p&gt;So the first two browsers know they both implement VP8 and VP9 and use that list of codecs when calling the &lt;a href=&quot;http://ortc.org/wp-content/uploads/2014/08/ortc.html#widl-RTCRtpSender-send-void-RTCRtpParameters-parameters&quot;&gt;RtpSenders .send method&lt;/a&gt; for the first time. That RtpSender object is another improvement that came from ORTC. If everything goes well, they will enjoy the superior quality of VP9.&lt;/p&gt;
&lt;p&gt;Now the third client joins, announcing only VP8 in the presence. That is a relatively compact thing which we can do like this using &lt;a href=&quot;https://github.com/otalk/stanza.io&quot;&gt;stanza.io&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sendPresence&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    caps&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        hash&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;sha-1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        node&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;http://talky.io/web&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        ver&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;QgayPKawpkPSDYmwT/WM94uAlu0=&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Based  on the short hash in the &apos;ver&apos; attribute, the clients that are already in the room (and the conference focus, which controls the video bridge) can determine that the new client does not support VP9 and can therefore switch the codec they are currently sending. To do that, they call the .send method again, removing VP9 from the list of codecs. No additional signaling is required.&lt;/p&gt;
&lt;p&gt;The same is true for the WebRTC PeerConnection API actually. Here, this would require an SDP renegotiation operation (all in the client, nothing goes over the wire) that removes VP9 from the list of supported codecs (by mangling the remote description and removing five lines -- or by just removing a single element in the JSON format we use for this). Still, it is much harder (at least for me) to come up with this conceptually and the ORTC description is easier to understand. I&apos;ll report further once we&apos;ve had a chance to play with VP9 more extensively.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Oh codecs. Say! You want to learn more stuff about things? So do we! Like for instance how to send you our email newsletter! Sign up below.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[On making design decisions]]></title><description><![CDATA[Articulating our decision making is a huge part of our jobs as designers. Every day we should be asking ourselves “Why did I decide to do it…]]></description><link>https://blog.andyet.com/2014/11/21/on-making-design-decisions/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/21/on-making-design-decisions/</guid><pubDate>Fri, 21 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Articulating our decision making is a huge part of our jobs as designers. Every day we should be asking ourselves “Why did I decide to do it this way?” Our coworkers, clients, and users will be asking the same question, so we may as well be prepared. &lt;/p&gt;
&lt;p&gt;Everything we add or leave out is the result of decision making. Sometimes we’re called to explain decisions around entire layouts and other times it’s just the exact shade of grey we chose for a horizontal rule. Big or small, it’s important to understand &lt;em&gt;why&lt;/em&gt; we land on the solutions we do.&lt;/p&gt;
&lt;p&gt;Below are six common decision patterns I’ve seen in my time as a designer. Note that these aren’t specifically ordered and I’m not suggesting any one is best. It’s important first to recognize our behavior before deciding what makes the most sense for our project which, as always, depends.&lt;/p&gt;
&lt;h3 id=&quot;decisions-made-by-other-people&quot;&gt;&lt;a href=&quot;#decisions-made-by-other-people&quot; aria-label=&quot;decisions made by other people permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decisions made by other people&lt;/h3&gt;
&lt;p&gt;On every project there will be plenty of decisions that have already been made for us. Most commonly this shows up as existing branding, usage rules, and style guides. An important decision we make is whether or not to adhere to these guidelines, for better or worse.&lt;/p&gt;
&lt;p&gt;Another way this pops up in our work is a client insisting on a certain direction, typeface, or various other treatment. How many times have you heard a designer say “That was the client’s decision” about negative feedback? Funny how we rarely use that one when the reviews are great. The truth is we made the decision that implementing their idea was better than continuing to push our idea or even to walk away from the project entirely. Decisions made by others are our decisions too.&lt;/p&gt;
&lt;h3 id=&quot;decisions-based-on-systems&quot;&gt;&lt;a href=&quot;#decisions-based-on-systems&quot; aria-label=&quot;decisions based on systems permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decisions based on systems&lt;/h3&gt;
&lt;p&gt;Designers and artists have been studying forms, trying new methods, and establishing systems for centuries. Many designers today use these proven systems to inform their decisions. &lt;a href=&quot;http://alistapart.com/article/more-meaningful-typography&quot;&gt;Typographic scales&lt;/a&gt; determine proper size measurements and rhythm, the &lt;a href=&quot;http://www.creativebloq.com/design/designers-guide-golden-ratio-12121546&quot;&gt;Golden Ratio&lt;/a&gt; influences aesthetic proportions, and the &lt;a href=&quot;http://www.cambridgeincolour.com/tutorials/rule-of-thirds.htm&quot;&gt;Rule of Thirds&lt;/a&gt; helps create balanced and dynamic compositions. I like to call this type of decision &lt;em&gt;leaning on history&lt;/em&gt;. &lt;/p&gt;
&lt;h3 id=&quot;decisions-based-on-personal-history&quot;&gt;&lt;a href=&quot;#decisions-based-on-personal-history&quot; aria-label=&quot;decisions based on personal history permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decisions based on personal history&lt;/h3&gt;
&lt;p&gt;Another type of history we lean on is our own project history. We sometimes make decisions based on what we’ve personally seen succeed or fail in the past. What worked on a previous project may work swimmingly for this one or horribly for another. As we know, every project has its own set of constraints and complexities.&lt;/p&gt;
&lt;h3 id=&quot;bandwagon-decisions&quot;&gt;&lt;a href=&quot;#bandwagon-decisions&quot; aria-label=&quot;bandwagon decisions permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bandwagon decisions&lt;/h3&gt;
&lt;p&gt;Many design decisions we make are influenced by what other people are doing. Copying what one designer is doing can be called plagiarism, but copying what lots of other designers are doing can be called &quot;following industry trends.&quot; There’s safety in numbers and making a bandwagon decision (following the path others have tested and approved) can make a lot of sense and save time. However, bandwagon decisions that reach ubiquity can lead to poor decisions about your specific project in the name of perceived standards. Love it or hate it, the &lt;a href=&quot;http://digiday.com/publishers/the-problem-with-the-hamburger-menu/&quot;&gt;hamburger menu&lt;/a&gt; is a great example.&lt;/p&gt;
&lt;h3 id=&quot;decisions-based-on-data&quot;&gt;&lt;a href=&quot;#decisions-based-on-data&quot; aria-label=&quot;decisions based on data permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decisions based on data&lt;/h3&gt;
&lt;p&gt;“Designed with science!” That’s how it can feel making design decisions based on data. Data gathered through user observation, interviews, and A/B testing can show us what’s working as intended and what isn’t. Decisions about which features to change or eliminate can naturally follow. Sometimes though, the data is poorly collected or it might not be very &lt;em&gt;meaningful&lt;/em&gt;. Designing contrary to what the data might suggest is a decision too.&lt;/p&gt;
&lt;h3 id=&quot;decisions-based-on-intuition&quot;&gt;&lt;a href=&quot;#decisions-based-on-intuition&quot; aria-label=&quot;decisions based on intuition permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decisions based on intuition&lt;/h3&gt;
&lt;p&gt;This type of decision can be hard to explain. It’s when we say something looks or feels “right.” A designer’s intuition is the sum of the observation, training, and practice they’ve accumulated over the length of their career. I suspect this is what people are referring to when they say someone has “a natural eye.” Sometimes there isn’t a specific system or data set or past project to point to. Sometimes the concept is brand new. This is when we make decisions based on intuition.&lt;/p&gt;
&lt;h3 id=&quot;decide-to-decide&quot;&gt;&lt;a href=&quot;#decide-to-decide&quot; aria-label=&quot;decide to decide permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Decide to decide&lt;/h3&gt;
&lt;p&gt;Any single decision can be informed by a combination of these approaches and many more not listed here. It’s important to know why we make decisions, but also to not let that knowledge paralyze us. No decision might seem better than a bad one, but at least with a bad decision we’ve learned something.&lt;/p&gt;
&lt;p&gt;If you’re a leader of a team, empower your designers (and your entire team, really) to make these hard decisions and to own the consequences. As much as indecision can damage a project or team, so can constantly asking for permission.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;What! That was awesome! Oh man, if only there was some way to get updates when more stuff like this comes out. Wait. Wait! I have an idea: sign up for our mailing list! Whew. That was a close one.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Efficient, consistent client-side apps with optimistic concurrency & JSON patch: part III — let's end this conflict!]]></title><description><![CDATA[Eons ago when our story first began, I told you how I needed to make a client app more consistent and efficient by implementing optimistic…]]></description><link>https://blog.andyet.com/2014/11/20/efficient-consistent-3/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/20/efficient-consistent-3/</guid><pubDate>Thu, 20 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Eons ago when our story first began, I told you how I needed to &lt;a href=&quot;http://blog.andyet.com/2014/11/06/optimistic-concurrency-and-json-patch&quot;&gt;make a client app more consistent and efficient&lt;/a&gt; by &lt;a href=&quot;http://blog.andyet.com/2014/11/13/optimistic-concurrency-II&quot;&gt;implementing optimistic concurrency and JSON Patch in our model layer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As I said before, in our app, we combine both of these forces for an efficiency and consistency one-two punch. As I worked through the integration and some other requirements, I realized that a third module that combined the previous two and added some sane defaults for conflict resolution would be really helpful, so I built one. It&apos;s called &lt;a href=&quot;https://www.npmjs.org/package/ampersand-model-optimistic-update-mixin&quot;&gt;ampersand-model-optimistic-update-mixin&lt;/a&gt;. Say that five times fast, or just call it AMOU (pronounced &quot;ammo&quot;).&lt;/p&gt;
&lt;h3 id=&quot;what-it-does&quot;&gt;&lt;a href=&quot;#what-it-does&quot; aria-label=&quot;what it does permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What it does&lt;/h3&gt;
&lt;p&gt;Let&apos;s recall our good buddy Franco from last time, and suppose that his data is edited by two different people working from the same base version:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// The original that both edits are based on&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Franco Witherspoon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;lastModified&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mon, 10 Nov 2014 14:32:08 GMT&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;createdBy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;car&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;make&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Honda&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CRX&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;modelYear&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2006&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;pants&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Levis&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;501&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Indigo&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bonobos&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Washed Chino&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Jet Blue&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;IZOD&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cotton Lounge&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Navy&quot;&lt;/span&gt;   
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Edit #1 (the one that gets saved while #2 is still editing)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Francis Withings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/car/model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CRX SiR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/pants/-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        manufacturer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alfani&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RED Slim-fit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Grey Sharkskin&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Edit #2&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Frank Withers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/car/model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CRX SiR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;remove&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/pants/2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &quot;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;pants&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        manufacturer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Joe Boxer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fleece Pajama&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Red Plaid&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;AMOU combines the features of &lt;a href=&quot;https://www.npmjs.org/package/ampersand-optimistic-sync&quot;&gt;AOS (ampersand-optimistic-sync)&lt;/a&gt; and &lt;a href=&quot;https://www.npmjs.org/package/ampersand-model-patch-mixin&quot;&gt;AMP (ampersand-model-patch-mixin)&lt;/a&gt; with its own special conflict-detection-and-resolution sauce. It does this by using AOS&apos;s version tracking and AMP&apos;s difference tracking to handle all ordinary situations, and then breaking out its Einstein-like problem solving skills when that rare–but deadly–&lt;code class=&quot;language-text&quot;&gt;sync:invalid-version&lt;/code&gt; event arises. When AMOU receives a &lt;code class=&quot;language-text&quot;&gt;sync:invalid-version&lt;/code&gt;, it will, by default, detect the differences between the current client and server states and trigger a &lt;code class=&quot;language-text&quot;&gt;sync:conflict&lt;/code&gt; event with a payload something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_conflict &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    conflicts&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        client&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Frank Withers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        server&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Francis Withings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        original&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Franco Witherspoon&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    serverState&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Franco Witherspoon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &amp;lt;-- conflicting change&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;lastModified&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Wed, 12 Nov 2014 04:58:08 GMT&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;createdBy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;car&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;make&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Honda&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CRX SiR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &amp;lt;-- matching change&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;modelYear&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2006&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;pants&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Levis&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;501&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Indigo&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bonobos&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Washed Chino&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Jet Blue&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;IZOD&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cotton Lounge&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Navy&quot;&lt;/span&gt;   
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alfani&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RED Slim-fit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Grey Sharkskin&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    resolved&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    unsaved&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Frank Withers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; original&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Franco Witherspoon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;remove&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/pants/2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; original&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;IZOD&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cotton Lounge&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Navy&quot;&lt;/span&gt;   
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/pants/-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            manufacturer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Joe Boxer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fleece Pajama&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Red Plaid&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; original&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This event payload gives you enough information to programmatically resolve the conflict or present the user with a dialog to allow them to manually resolve the conflict. AMOU doesn&apos;t stop there, though. With one or two configuration tweaks, AMOU can resolve most conflicts for you and your users, making life easier still.&lt;/p&gt;
&lt;h3 id=&quot;how-to-use-it&quot;&gt;&lt;a href=&quot;#how-to-use-it&quot; aria-label=&quot;how to use it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to use it&lt;/h3&gt;
&lt;p&gt;The default functionality is very simple:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AMOU&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-model-optimistic-update-mixin&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; BaseModel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-model&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OR require(&apos;backbone&apos;).Model;&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AMOU&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    props&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; age&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    children&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;car&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Car&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    collections&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;pants&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Pants&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you need to adjust the config for AOS, AMP, or AMOU itself, you&apos;ll need to pass in an &lt;code class=&quot;language-text&quot;&gt;_optimisticUpdate&lt;/code&gt; config object:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AMOU&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-model-optimistic-update-mixin&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; BaseModel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-model&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// OR require(&apos;backbone&apos;).Model;&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AMOU&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    props&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; age&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    children&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;car&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Car&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    collections&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;pants&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Pants&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    _optimisticUpdate&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        patcher&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* AMP config */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        optimistic&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* AOS config */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        autoResolve&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        JSONPatch&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        ignoreProps&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        collectionSort&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        customCompare&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// prop/child/collection: function (original, current) {} map where the func returns true when considered equal, false when not, or an array of operations to make original match current&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Things really get interesting when you set the &lt;code class=&quot;language-text&quot;&gt;autoResolve&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;&amp;#39;server&amp;#39;&lt;/code&gt;. When you set &lt;code class=&quot;language-text&quot;&gt;autoResolve&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt;, AMOU resolves all non-conflicting changes. It then triggers a &lt;code class=&quot;language-text&quot;&gt;sync:conflict-autoResolved&lt;/code&gt; event when all differences are not conflicting or a &lt;code class=&quot;language-text&quot;&gt;sync:conflict&lt;/code&gt; event when there are conflicts. When you set &lt;code class=&quot;language-text&quot;&gt;autoResolve&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;&amp;#39;server&amp;#39;&lt;/code&gt;, all conflicts are resolved in favor of the server&apos;s version and the &lt;code class=&quot;language-text&quot;&gt;sync:conflict-autoResolved&lt;/code&gt; event triggered.&lt;/p&gt;
&lt;p&gt;When &lt;code class=&quot;language-text&quot;&gt;autoResolve&lt;/code&gt; is set to true, the &lt;code class=&quot;language-text&quot;&gt;sync:conflict&lt;/code&gt; payload from above would be a little different, because the new pair of Alfani pants would automatically be added to the local pants collection and be recorded in the payload&apos;s &lt;code class=&quot;language-text&quot;&gt;resolved&lt;/code&gt; array.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_conflict &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    conflicts&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* same as above */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    serverState&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* same as above */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    resolved&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/pants/-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        manufacturer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alfani&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RED Slim-fit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Grey Sharkskin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        client&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; clientDiscarded&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    unsaved&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* same as above */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If your business rules say that the server should always win in case of conflicts, as they did in my project, simply set &lt;code class=&quot;language-text&quot;&gt;autoResolve&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;&amp;#39;server&amp;#39;&lt;/code&gt; and the server&apos;s version will be overwrite any conflicting local changes and a &lt;code class=&quot;language-text&quot;&gt;sync:conflict-autoResolved&lt;/code&gt; event will fire with this payload:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_conflict &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    conflicts&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* none because we&apos;ve resolved them in the server&apos;s favor */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    serverState&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* same as above */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    resolved&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Francis Withings&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            client&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Frank Withers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; clientDiscarded&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &quot;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;pants&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            manufacturer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Alfani&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RED Slim-fit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Grey Sharkskin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            client&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; clientDiscarded&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    unsaved&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;remove&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/pants/2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; original&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;IZOD&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cotton Lounge&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Navy&quot;&lt;/span&gt;   
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/pants/-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            manufacturer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Joe Boxer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fleece Pajama&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Red Plaid&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; original&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In addition to &lt;code class=&quot;language-text&quot;&gt;autoResolve&lt;/code&gt; there are a few other configuration directives that may be helpful to you. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;JSONPatch&lt;/code&gt;: if your server doesn&apos;t support JSON Patch, you can disable that feature and still get the optimistic concurrency and conflict resolution benefits by setting this directive to &lt;code class=&quot;language-text&quot;&gt;JSONPatch: false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ignoreProps&lt;/code&gt;: does your server create, update, and send data that your client-side ignores? Add those props to this directive: &lt;code class=&quot;language-text&quot;&gt;ignoreProps: [&amp;#39;createdBy&amp;#39;, &amp;#39;lastModified&amp;#39;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;collectionSort&lt;/code&gt;: do you sort child collections by &lt;code class=&quot;language-text&quot;&gt;name&lt;/code&gt;, but the server sorts them by &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;? No problem! Just add &lt;code class=&quot;language-text&quot;&gt;collectionSort: {default: &amp;#39;id&amp;#39;}&lt;/code&gt; to your config. You can also set per-collection sorting by setting &lt;code class=&quot;language-text&quot;&gt;collectionName: &amp;#39;property&amp;#39;&lt;/code&gt;. This directive also accepts functions that conforms to the Javascript Array.prototype.sort API. &lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;customCompare&lt;/code&gt;: does your server send you some really wacky data for one of your child models or props that needs a lot of massaging to determine what is different? This directive takes prop, child model, and child collection names with a function that accepts the original and current data and returns true to indicate that they are equivalent, false if not, or an array of operations to make original into current: &lt;code class=&quot;language-text&quot;&gt;function (original, current) {}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The final tool that AMOU gives developers is the &lt;code class=&quot;language-text&quot;&gt;reverseUnsaved&lt;/code&gt; method. Taking the payload of either &lt;code class=&quot;language-text&quot;&gt;sync:conflict&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;sync:conflict-autoResolved&lt;/code&gt;, it will roll back all unsaved local changes in place. This allows you to automatically roll back unsaved changes, if that&apos;s what your business rules dictate or in response to user action. To do auto-rollback, simply subscribe it to the events in your &lt;code class=&quot;language-text&quot;&gt;initialize&lt;/code&gt; method: &lt;code class=&quot;language-text&quot;&gt;this.listenTo(this, &amp;#39;sync:conflict sync:conflict-autoResolved&amp;#39;, this.reverseUnsaved)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So there you have it: three tools to help you make client-side JavaScript apps that use Ampersand or Backbone more consistent, efficient, AND user-friendly. I hope you have enjoyed reading this series as much as I have enjoyed writing it. Please feel free to give me a shout on &lt;a href=&quot;https://twitter.com/aaronmccall&quot;&gt;Twitter&lt;/a&gt;, if you have any questions or just want to tell me how much fun writing JavaScript is. Ciao!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Want to learn even more stuff like this? How about some general goings-on to boot? Then sign up for our email list below!&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Tao of Ops: Managing code changes]]></title><description><![CDATA[A core tenet of any Operations Team is that you must enable developers to change their code with confidence. For the developer this means…]]></description><link>https://blog.andyet.com/2014/11/19/managing-code-changes/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/19/managing-code-changes/</guid><pubDate>Wed, 19 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A core tenet of any Operations Team is that you must enable developers to change their code with confidence. For the developer this means they have the flexibility to try new things or to change old, broken code. Unfortunately, however, with every code change comes the risk of breaking production systems, which is something Operations has to manage. A great way to balance these needs is to continuously test new code as close to the point of change as possible by reacting to code commits as they happen.&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;http://andyet.com&quot;&gt;&amp;#x26;yet&lt;/a&gt; the majority of the code that is deployed to production servers is written in &lt;a href=&quot;http://nodejs.org/&quot;&gt;NodeJS&lt;/a&gt;, so that&apos;s the example I&apos;ll use. NodeJS uses &lt;a href=&quot;https://www.npmjs.org&quot;&gt;npm&lt;/a&gt; as its package manager, and one aspect of npm is its ability to define scripts that are to be run at various stages of the package&apos;s lifetime. To make full use of this feature we need a way to run the defined scripts at the point that a developer is commiting code, as that is the best time to do validation and testing of the newly changed code.&lt;/p&gt;
&lt;p&gt;Fortunately an npm package exists that will do just that - &lt;a href=&quot;https://www.npmjs.org/package/precommit-hook&quot;&gt;precommit-hook&lt;/a&gt;. It installs the required pre-commit hook into your project&apos;s .git metadata such that just before git actually performs the commit, it will run the defined set of scripts or run the lint, validate, and test scripts by default. We can use this to run any check we need, but for now I will describe how to run a script to scan the project&apos;s dependencies for any known security vulnerabilities using &lt;a href=&quot;https://www.npmjs.org/package/retire&quot;&gt;retire.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First we need to add &lt;code class=&quot;language-text&quot;&gt;retire.js&lt;/code&gt; to the project&apos;s package.json and add a reference to it so the pre-commit hook will run it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;{
    &amp;quot;name&amp;quot;: &amp;quot;example app&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;an example&amp;quot;,
    &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,
    &amp;quot;devDependencies&amp;quot;: {
      &amp;quot;retire&amp;quot;: &amp;quot;~0.3.2&amp;quot;,
      &amp;quot;precommit-hook&amp;quot;: &amp;quot;~1.0.7&amp;quot;
    },
    &amp;quot;scripts&amp;quot;: {
      &amp;quot;validate&amp;quot;: &amp;quot;retire -n -j&amp;quot;
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;precommit-hook&lt;/code&gt; will install itself into git and will trigger the running of &lt;code class=&quot;language-text&quot;&gt;retire -n -j&lt;/code&gt; during the commit process, which will then scan the project for any known vulnerabilities. Another variation on this theme would be to run the &lt;code class=&quot;language-text&quot;&gt;validate&lt;/code&gt; script during the build/test portion of a Continuous Integration process, but that would take a much longer blog post to describe. Using &lt;code class=&quot;language-text&quot;&gt;precommit-hook&lt;/code&gt; is a great way to show both it and &lt;code class=&quot;language-text&quot;&gt;retire.js&lt;/code&gt; in action.&lt;/p&gt;
&lt;p&gt;(By the way, for a more in-depth look at what &lt;code class=&quot;language-text&quot;&gt;retire.js&lt;/code&gt; can do, head on over to the ^Lift Security &lt;a href=&quot;https://blog.liftsecurity.io/2014/11/19/bower-components-with-known-vulnerabilities&quot;&gt;article on retire.js&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;It is always a good thing when you can enable developers to do their work while also ensuring that the Operations Team can continue on their path. Tools like &lt;code class=&quot;language-text&quot;&gt;precommit-hook&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;retire.js&lt;/code&gt; enable both teams to be confident that they are heading in the right direction.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Enjoying the Tao of Ops as much as we are? Then why not sign up for our mailing list for other good stuff?&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Why we're excited about ORTC]]></title><description><![CDATA[Microsoft recently announced they will support Object RTC and now everyone is talking about ORTC and how they will support it. What is this…]]></description><link>https://blog.andyet.com/2014/11/18/ortc/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/18/ortc/</guid><pubDate>Tue, 18 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Microsoft &lt;a href=&quot;http://blogs.skype.com/2014/10/27/bringing-interoperable-real-time-communications-to-the-web/&quot;&gt;recently announced&lt;/a&gt; they will support &lt;a href=&quot;http://ortc.org/&quot;&gt;Object RTC&lt;/a&gt; and now everyone is talking about ORTC and how they will support it. &lt;/p&gt;
&lt;p&gt;What is this all about and what is ORTC anyway? &lt;/p&gt;
&lt;p&gt;In essence, ORTC is an alternative API for &lt;a href=&quot;http://www.webrtc.org/&quot;&gt;WebRTC&lt;/a&gt;. It is object-oriented and protects developers from all that ugly Session Description Protocol (SDP) madness. Some people call it WebRTC 1.1, or maybe WebRTC 2.0.&lt;/p&gt;
&lt;p&gt;So... will &lt;a href=&quot;https://andyet.com/&quot;&gt;&amp;#x26;yet&lt;/a&gt; (and &lt;a href=&quot;https://otalk.org/&quot;&gt;Otalk&lt;/a&gt;) (and &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt;) support ORTC? Of course!&lt;/p&gt;
&lt;p&gt;Mostly because we have a use case where ORTC is better than the proprietary ways of solving certain problems with the WebRTC Peerconnection API. Instead of telling you how much we like ORTC, let me tell you about the problems we&apos;ve experienced with WebRTC as it stands today.&lt;/p&gt;
&lt;h2 id=&quot;sdp&quot;&gt;&lt;a href=&quot;#sdp&quot; aria-label=&quot;sdp permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SDP&lt;/h2&gt;
&lt;p&gt;ORTC gets rid of the SDP API surface used in the WebRTC PeerConnection API. Being XMPP people, we prefer Jingle over SDP. However, we rarely touch SDP at all, due to the magnificent &lt;a href=&quot;https://github.com/otalk/sdp-jingle-json/&quot;&gt;sdp-jingle-json module&lt;/a&gt; that &lt;a href=&quot;https://andyet.com/team/lance&quot;&gt;Lance Stout&lt;/a&gt; wrote. &lt;/p&gt;
&lt;p&gt;This module transforms SDP into a JSON object and back. The object structure makes it somewhat easier to manipulate the description and change things. Still, you need to know about the semantics of the things you are manipulating. Removing SDP is not something we strongly care about. We&apos;ve hidden it well by  burying under layers of abstractions, and we are not using it on the wire.&lt;/p&gt;
&lt;h2 id=&quot;capability-and-parameter-negotiation&quot;&gt;&lt;a href=&quot;#capability-and-parameter-negotiation&quot; aria-label=&quot;capability and parameter negotiation permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Capability and Parameter Negotiation&lt;/h2&gt;
&lt;p&gt;One of the most important aspects I learned about recently is that ORTC distinguishes between capabilities and negotiation through the RTPSenders static &lt;a href=&quot;http://ortc.org/wp-content/uploads/2014/08/ortc.html#widl-RTCRtpSender-getCapabilities-RTCRtpCapabilities-DOMString-kind&quot;&gt;getCapabilities&lt;/a&gt; method.&lt;/p&gt;
&lt;p&gt;Capabilities allow us to query the capabilities of an implementation, e.g. what video codecs it supports, whether it can multiplex everything on a single UDP port pair, etc. Being static it means we can query those capabilities without creating an RTPSender. And we can also figure out if two clients would be compatible with each other beforehand.&lt;/p&gt;
&lt;p&gt;Negotiation on the other hand means that two entities (who supposedly have a common capability) decide to use it for a particular session. That is what the &lt;a href=&quot;http://tools.ietf.org/html/rfc3264&quot;&gt;Offer-Answer-Model for SDP&lt;/a&gt; was all about. Your offer tells me what you support and want to use and I answer with the subset I want to use. &lt;/p&gt;
&lt;p&gt;Both capabilities and negotiation are useful and necessary. Capabilities are harder to determine in the PeerConnection API, even though it&apos;s not impossible. ORTC just makes the distinction more clear and lets us think about how that distinction influences the protocols we design. However, as we saw with Jingle, cool features like &lt;a href=&quot;http://www.xmpp.org/extensions/xep-0176.html&quot;&gt;trickle ICE&lt;/a&gt; can be &lt;a href=&quot;http://www.xmpp.org/extensions/xep-0176.html&quot;&gt;backported to SDP&lt;/a&gt; semantics.&lt;/p&gt;
&lt;h2 id=&quot;talky&quot;&gt;&lt;a href=&quot;#talky&quot; aria-label=&quot;talky permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Talky&lt;/h2&gt;
&lt;p&gt;We&apos;ve previously &lt;a href=&quot;https://blog.andyet.com/2014/10/22/Talky-2-is-Coming&quot;&gt;written about the upcoming new version of Talky&lt;/a&gt;. It&apos;s a multiuser conferencing application that, like Jitsi Meet, uses the Jitsi Videobridge and XMPP. Currently it only works in Chrome (no worries, we&apos;re talking with Mozilla).&lt;/p&gt;
&lt;p&gt;There are two different problems here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;multiparty conferencing and&lt;/li&gt;
&lt;li&gt;upgrading a 1-1 call to a conference&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;multiparty-conferencing&quot;&gt;&lt;a href=&quot;#multiparty-conferencing&quot; aria-label=&quot;multiparty conferencing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Multiparty Conferencing&lt;/h2&gt;
&lt;p&gt;In terms of API usage it is more complex than anything out there (until Hangouts came about), doing all kinds of renegotiation, adding and removing remote streams for participants. Chrome enables this through an SDP variant known as &lt;a href=&quot;https://tools.ietf.org/html/draft-uberti-rtcweb-plan-00&quot;&gt;Plan B&lt;/a&gt; which did not get accepted by the IETF last year. Although that did not Chrome from implementing it.&lt;/p&gt;
&lt;p&gt;Basically to add or remove a local audio/video stream you need to do a setRemoteDescription call followed by a setLocalDescription which will trigger an onaddstream and onremovestream callback depending on whether any streams were added or removed. If you want to know all the gory details, please refer to the &lt;a href=&quot;http://webrtchacks.com/hangout-analysis-philipp-hancke/&quot;&gt;webrtchacks article I wrote on how Hangouts uses this API&lt;/a&gt;. Not very surprising, the features needed were already in Chrome because they were required for Hangouts. &lt;/p&gt;
&lt;p&gt;Hangouts also uses some advanced features like simulcast (i.e., sending different resolutions of the same video) which are activated by adding some special lines to the SDP. That&apos;s currently completely undocumented and basically black magic. What is also lacking is a way to prioritize streams when several are competing for bandwidth.&lt;/p&gt;
&lt;p&gt;Implementing Talky with the current API is possible. However, one should note that &quot;the current API&quot; here includes a number of non-standard proprietary features. And using it felt like jumping through hoops.&lt;/p&gt;
&lt;p&gt;How will ORTC change this?&lt;/p&gt;
&lt;p&gt;Well, first we don&apos;t need to do a setRemoteDescription-setLocalDescription dance. Instead of getting streams (typically consisting of an audio and a video stream) pushed we can use the &lt;a href=&quot;http://ortc.org/wp-content/uploads/2014/08/ortc.html#rtcrtpreceiver&quot;&gt;RTPReceiver&lt;/a&gt; API to pull audio or video tracks from the peer connection after setting them up with certain parameters (we want to associate those tracks with the participants in the chatroom). There is also a mode for &lt;a href=&quot;http://ortc.org/wp-content/uploads/2014/08/ortc.html#rtcrtpunhandledevent-interface-definition&quot;&gt;detecting unhandled RTP streams&lt;/a&gt; which potentially allows us to get rid of signaling for individual participants.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://ortc.org/wp-content/uploads/2014/08/ortc.html#rtcrtpsender&quot;&gt;RTPSender&lt;/a&gt; objects allow for better control and prioritization of streams. Note that these RTPSender objects are now part of the &quot;1.0&quot; WebRTC API as well and Mozilla has already implemented them. So you can solve that problem there, too.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-a-1-1-call-to-a-multiparty-conference&quot;&gt;&lt;a href=&quot;#upgrading-a-1-1-call-to-a-multiparty-conference&quot; aria-label=&quot;upgrading a 1 1 call to a multiparty conference permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Upgrading a 1-1 Call to a Multiparty Conference&lt;/h2&gt;
&lt;p&gt;Quite a sizable portion of the current Talky usage is for 1-1 sessions which are peer-to-peer (with a small percentage being relayed through TURN servers). We do not want to route those sessions via the Jitsi Videobridge for a number of reasons. First, it costs us more money. Second, it decrypts the call and we don&apos;t really want to have access to your private conversations. Third, it increases the latency, which affects the quality of the user experience.&lt;/p&gt;
&lt;p&gt;So what we actually want to do is to have your 1-1 sessions in peer-to-peer mode and upgrade to a call relayed by the bridge as necessary. In theory, the current PeerConnection API allows this by doing something called an &quot;ICE restart&quot;. You open a new media path to the bridge and switch over once it&apos;s connected. Turns out that this is currently &lt;a href=&quot;https://code.google.com/p/webrtc/issues/detail?id=3618&quot;&gt;not implemented by Chrome&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;How will ORTC change this?&lt;/p&gt;
&lt;p&gt;Well, in ORTC this scenario is easier to describe thanks to the better vocabulary. To do a switch like this, you setup another &lt;a href=&quot;http://ortc.org/wp-content/uploads/2014/08/ortc.html#rtcicetransport&quot;&gt;RTCIceTransport&lt;/a&gt; and &lt;a href=&quot;http://ortc.org/wp-content/uploads/2014/08/ortc.html#rtcdtlstransport&quot;&gt;RTCDtlsTransport&lt;/a&gt; object, wait for the connection to become active (by waiting for a &lt;a href=&quot;https://rtcdtlstransportstatechangedevent/&quot;&gt;RTCDtlsTransportStateChanged&lt;/a&gt; event on both sides) and then attach your RTPSender to that new transport.&lt;/p&gt;
&lt;p&gt;Just having the right vocabulary to talk about this makes ORTC worthwhile.&lt;/p&gt;
&lt;h2 id=&quot;bugs&quot;&gt;&lt;a href=&quot;#bugs&quot; aria-label=&quot;bugs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Bugs&lt;/h2&gt;
&lt;p&gt;When you implement applications on top of the PeerConnection API in Chrome or Firefox you will notice some bugs (if not you&apos;re probably only doing boring stuff).  I ended up with reporting more than 50 Chrome bugs (and a few Firefox ones) in the last two years.&lt;/p&gt;
&lt;p&gt;How will ORTC change this?&lt;/p&gt;
&lt;p&gt;Well, with the Microsoft announcement I look forward to filing bugs against a third browser. 50% more fun!&lt;/p&gt;
&lt;p&gt;When I tried the plugin Microsoft Open Tech released earlier this year it took half an hour to find two bugs.&lt;/p&gt;
&lt;p&gt;Once Google adds ORTC as an API surface there will be more bugs there and they will have two API surfaces to support. This is rather going to slow them down. And according to the &lt;a href=&quot;http://bloggeek.me/google-roadmap-webrtc/&quot;&gt;roadmap&lt;/a&gt; we should already have several ORTC elements in the current Chrome 38 which are not even in Canary yet.&lt;/p&gt;
&lt;h2 id=&quot;tldr&quot;&gt;&lt;a href=&quot;#tldr&quot; aria-label=&quot;tldr permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;ORTC will make some applications easier. Although it&apos;s not a magic bullet that will somehow fix all the problems that exist with the PeerConnection API, it looks good on paper and we&apos;re excited about playing with running code once it ships in the browsers (especially IE).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Want more cool stuff like this? Then sign up for our newsletter below. It&apos;s full of Vitamin I...for interest!&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Lead by listening]]></title><description><![CDATA[The most important job of a leader is to listen and listen well. What sets a great leader is her willingness to give of her time and energy…]]></description><link>https://blog.andyet.com/2014/11/14/lead-by-listening/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/14/lead-by-listening/</guid><pubDate>Fri, 14 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The most important job of a leader is to listen and listen well. What sets a great leader is her willingness to give of her time and energy. And although listening requires a large amount of both time and energy, it makes people feel valued and needed, a goal which all leaders should aspire to. &lt;/p&gt;
&lt;p&gt;Leaders need to have–or learn to develop–the humility it takes to truly listen.  Not just to hear what people are saying directly, but to be an investigative listener, to pay attention and discover things in the organization that may be unseen, whether they be positive and negative. And if you do uncover a dark, hard problem, fear not! Chances are good that the solution is shrouded in wisdom which will serve you well in the future.&lt;/p&gt;
&lt;p&gt;What other good can you do by listening? Well, the list is probably way longer than this, but here are a few gems I&apos;ve discovered along the way. I&apos;m sure you&apos;ll find your own treasure, too.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You create and build trust&lt;/li&gt;
&lt;li&gt;You learn to trust the team&lt;/li&gt;
&lt;li&gt;You build confidence&lt;/li&gt;
&lt;li&gt;You discover and support people&apos;s passion for their own personal growth&lt;/li&gt;
&lt;li&gt;You inspire collaboration&lt;/li&gt;
&lt;li&gt;You empower the PEOPLE&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We communicate something powerful and sustaining by simply opening our ears instead of our mouths. But it&apos;s not just about that, either; it&apos;s about being patient and learning how to better ask questions so people feel encouraged to share their honest thoughts. In doing so, you have incredible power to improve the well being and health of not only your teammates, but your organization as a whole. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Want more nuggets of wisdom from cool people like Stephanie? Then sign up for our email list! (P.S. Yes Stephanie, you are cool and full of wisdom. DEAL WITH IT.)&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Efficient, consistent client-side apps with optimistic concurrency & JSON patch: part II]]></title><description><![CDATA[Today's entry: Building the Mixins!This post is second in a three part series that I started with a little bit of background last week…]]></description><link>https://blog.andyet.com/2014/11/13/optimistic-concurrency-II/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/13/optimistic-concurrency-II/</guid><pubDate>Thu, 13 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today&apos;s entry: Building the Mixins!&lt;/p&gt;
&lt;p&gt;This post is second in a three part series that I &lt;a href=&quot;http://blog.andyet.com/2014/11/06/optimistic-concurrency-and-json-patch&quot;&gt;started with a little bit of background&lt;/a&gt; last week.&lt;/p&gt;
&lt;h2 id=&quot;building-the-optimistic-concurrency-mixin&quot;&gt;&lt;a href=&quot;#building-the-optimistic-concurrency-mixin&quot; aria-label=&quot;building the optimistic concurrency mixin permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Building the optimistic concurrency mixin&lt;/h2&gt;
&lt;p&gt;Following the &lt;a href=&quot;http://humanjavascript.com/&quot;&gt;Human way&lt;/a&gt;, I made the optimistic concurrency mixin a CommonJS module and published it with npm. It&apos;s called &lt;a href=&quot;https://www.npmjs.org/packages/ampersand-optimistic-sync&quot;&gt;ampersand-optimistic-sync&lt;/a&gt;, but we&apos;ll call it AOS here.  AOS replaces the sync method on your Backbone or Ampersand models. Since sync is the core Ajax method, extending there allows AOS to read and write the versioning headers it needs.&lt;/p&gt;
&lt;p&gt;AOS supports both the ETag/If-Match and Last-Modified/If-Unmodified-Since approaches for the version information with ETag being the default.&lt;/p&gt;
&lt;h3 id=&quot;what-it-does&quot;&gt;&lt;a href=&quot;#what-it-does&quot; aria-label=&quot;what it does permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What it does&lt;/h3&gt;
&lt;p&gt;Regardless of HTTP verb (GET, POST, PUT, DELETE, PATCH), AOS interrogates the server&apos;s response for the configured version header (ETag or Last-Modified), and stores the header&apos;s value on the model in a &lt;code class=&quot;language-text&quot;&gt;_version&lt;/code&gt; property and triggers a &lt;code class=&quot;language-text&quot;&gt;sync:version&lt;/code&gt; event with the model and the version data as payload. Then on any updating requests (PUT or PATCH), AOS adds the appropriate request header with the &lt;code class=&quot;language-text&quot;&gt;_version&lt;/code&gt; data as its value.&lt;/p&gt;
&lt;p&gt;When the server will respond with a &lt;a href=&quot;http://tools.ietf.org/html/rfc7232#section-4.2&quot;&gt;412 - Pre-Condition Failed&lt;/a&gt; error status due to an invalid version, AOS triggers a &lt;code class=&quot;language-text&quot;&gt;sync:invalid-version&lt;/code&gt; event with the model, new version, and any JSON response data. This event allows the developer to handle invalid-version scenarios as needed.&lt;/p&gt;
&lt;h3 id=&quot;how-to-use-it&quot;&gt;&lt;a href=&quot;#how-to-use-it&quot; aria-label=&quot;how to use it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to use it&lt;/h3&gt;
&lt;p&gt;Adding AOS&apos;s functionality to Ampersand models is as easy as:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; BaseModel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-model&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AOS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-optimistic-sync&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BaseModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AOS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&apos;s pretty easy, but maybe it doesn&apos;t give you exactly what you want. No worries though; you can do a bit of configuring:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; BaseModel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;backbone&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Model&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AOS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-optimistic-sync&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BaseModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AOS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// [default], &apos;last-modified&apos; is also supported&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;etag&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// pre-define a handler for the sync:invalid-version event &lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;invalidHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;model&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; version&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; response&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// make the most of a bad situation&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// pre-define default sync options&lt;/span&gt;
    options&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        all&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// any options you&apos;d like to set for all requests&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// you can also set options for particular methods&lt;/span&gt;
        create&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function-variable function&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;// do stuff with data&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        read&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        update&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            patch&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that I had a way to track versions and set a handler for invalid version events, it was time to work on the JSON Patch implementation.&lt;/p&gt;
&lt;h2 id=&quot;building-the-json-patch-mixin&quot;&gt;&lt;a href=&quot;#building-the-json-patch-mixin&quot; aria-label=&quot;building the json patch mixin permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Building the JSON Patch mixin&lt;/h2&gt;
&lt;p&gt;Once again, I created a CommonJS module and published it with npm as &lt;a href=&quot;https://www.npmjs.org/package/ampersand-model-patch-mixin&quot;&gt;ampersand-model-patch-mixin&lt;/a&gt;. Rather than keep saying that mouthful, I&apos;ll refer to it as AMP for the rest of the post. &lt;/p&gt;
&lt;h3 id=&quot;what-it-does-1&quot;&gt;&lt;a href=&quot;#what-it-does-1&quot; aria-label=&quot;what it does 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What it does&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;It keeps track of the last known server state for the model, so it can calculate differences.&lt;/li&gt;
&lt;li&gt;It generates JSON Patch operations as model data changes.&lt;/li&gt;
&lt;li&gt;It generates op-count events to let devs know how many it has tracked.&lt;/li&gt;
&lt;li&gt;It enables setting an autoSave test that will trigger a save based on the op-count event.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;how-to-use-it-1&quot;&gt;&lt;a href=&quot;#how-to-use-it-1&quot; aria-label=&quot;how to use it 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to use it&lt;/h3&gt;
&lt;p&gt;The basics are simple. Given a pretty standard Ampersand model with a child model and a child collection, we would do the following:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; BaseModel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;backbone&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Model&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Car &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./car&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Pants &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;../collections/pants&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;AMP&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-model-patch-mixin&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// A simple person model&lt;/span&gt;
module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BaseModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    props&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; age&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    children&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;car&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Car&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    collections&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;pants&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Pants&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let&apos;s assume that we fetch the record for Person 1 and make some changes:&lt;/p&gt;
&lt;p&gt;&lt;a name=&quot;patcher-example&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;../models/person&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; person &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Server&apos;s response&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Franco Witherspoon&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;lastModified&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mon, 10 Nov 2014 14:32:08 GMT&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;createdBy&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;car&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;make&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Honda&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CRX&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;modelYear&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2006&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;pants&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Levis&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;501&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Indigo&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bonobos&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Washed Chino&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Jet Blue&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;manufacturer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;IZOD&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Cotton Lounge&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;size&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;color&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Navy&quot;&lt;/span&gt;   
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// AMP stores the response data at the property specified by its originalProperty config directive (default: _original).&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Identity is so fluid these days!&lt;/span&gt;
person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Frank Withers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Let&apos;s be specific.&lt;/span&gt;
person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;car&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;model &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; SiR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Frank loved those IZOD&apos;s, but their time had come.&lt;/span&gt;
person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pants&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pants&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Gotta have PJ pants.&lt;/span&gt;
person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pants&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    manufacturer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Joe Boxer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fleece Pajama&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Blue Plaid&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Wait! Not blue, red.&lt;/span&gt;
person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pants&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;color &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Red Plaid&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_ops&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; 4&lt;/span&gt;

person&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Sends the following to the server with Content-Type: application/json+patch&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Frank Withers&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/car/model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CRX SiR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;remove&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/pants/2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;op&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/pants/-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        manufacturer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Joe Boxer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fleece Pajama&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; color&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Red Plaid&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that there are only four operation objects despite our having made five changes. AMP collapses changes to new models—ones that already have an add operation—into the add operation because their path is unknown. In order to do this, AMP stores the model&apos;s cid in its internal &lt;code class=&quot;language-text&quot;&gt;_ops&lt;/code&gt; array. This also allows child collections to have a different sort order than the server&apos;s.&lt;/p&gt;
&lt;p&gt;&quot;What about this auto-save business you mentioned earlier?&quot; you ask. Let&apos;s talk about that. You can set up auto-saving when AMP reaches five operations like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BaseModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    _patcherConfig&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        autoSave&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    props&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; age&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    children&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;car&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Car&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    collections&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;pants&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Pants&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you need more control, you can also set &lt;code class=&quot;language-text&quot;&gt;autoSave&lt;/code&gt; to a function that returns truthily when you want to save:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BaseModel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AMP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BaseModel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    _patcherConfig&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function-variable function&quot;&gt;autoSave&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;model&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opCount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// Returns true if 5 total&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;opCount &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; roots &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// Returns true if more than three different root paths in ops&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_ops&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; root &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; op&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;roots&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; roots&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;roots&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    props&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; age&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    children&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;car&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Car&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    collections&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;pants&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Pants&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;the-end-or-a-hint-of-things-to-come&quot;&gt;&lt;a href=&quot;#the-end-or-a-hint-of-things-to-come&quot; aria-label=&quot;the end or a hint of things to come permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The End or a Hint of Things to Come?&lt;/h2&gt;
&lt;p&gt;As I said before, in our app we need to combine both of these forces for a efficiency and consistency one-two punch. But as I worked through the integration and some other requirements, I realized that a third module that combined the previous two and added some sane defaults for conflict resolution would be really helpful, so I built one. It&apos;s called &lt;a href=&quot;https://www.npmjs.org/package/ampersand-model-optimistic-update-mixin&quot;&gt;ampersand-model-optimistic-update-mixin&lt;/a&gt;, and it&apos;s a powerhouse, but to hear its story you&apos;ll have to wait for the next shot: &quot;Part Three: Let&apos;s End This Conflict!&quot;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Want to learn even more stuff like this? How about some general goings-on to boot? Then sign up for our email list below!&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Tao of Ops: TLS certificate testing]]></title><description><![CDATA["If you don't monitor it, you can't manage it."In the last installment of our Tao of Ops series I pointed out the above maxim as being a…]]></description><link>https://blog.andyet.com/2014/11/12/tls-certificate-testing/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/12/tls-certificate-testing/</guid><pubDate>Wed, 12 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&quot;If you don&apos;t monitor it, you can&apos;t manage it.&quot;&lt;/p&gt;
&lt;p&gt;In the last installment of our Tao of Ops series I pointed out the above maxim as being a variation on the business management saying, &quot;You can&apos;t manage what you can&apos;t measure&quot; (often attributed to Peter Drucker). This has become one of the core principles I try to keep in mind while walking the Operations path.&lt;/p&gt;
&lt;p&gt;Keeping this in mind, today I want to tackle testing the TLS Certificates that can be found everywhere in any shop doing web related production - something that needs to be done and can be rather involved in order to do properly.&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://en.wikipedia.org/wiki/Transport_Layer_Security&quot;&gt;Wikipedia&lt;/a&gt; TLS Certificates are:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Transport Layer Security (TLS) and its predecessor, Secure Sockets Layer (SSL), are cryptographic protocols designed to provide communication security over the Internet. They use X.509 certificates and hence asymmetric cryptography to authenticate the counterparty with whom they are communicating, and to exchange a symmetric key. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When it comes to anything that involves security - verifying is never going to be simple, and if it looks simple, then it&apos;s time to take a step back and ask yourself what you&apos;re missing. Crypto is &lt;em&gt;hard&lt;/em&gt; and the code tends to be rather long, so I will be showing snippets of code below taken from &lt;a href=&quot;https://github.com/bear/kenkou&quot;&gt;kenkou&lt;/a&gt;, which is a site checking tool I&apos;ve written that uses the Python &lt;a href=&quot;https://pypi.python.org/pypi/pyOpenSSL&quot;&gt;pyOpenSSL&lt;/a&gt; library.&lt;/p&gt;
&lt;p&gt;With the above definition and warnings fresh in our minds, let&apos;s take a look at what&apos;s required to make sure that your web site&apos;s certificate is valid. For the purposes of today&apos;s post we are going to limit the scope to: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Whether or not all of the certificates in the chain returned are themselves valid&lt;/li&gt;
&lt;li&gt;Is the peer certificate itself not expired&lt;/li&gt;
&lt;li&gt;Does the domain name match the hostname(s) within the certificate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From &lt;code class=&quot;language-text&quot;&gt;checkCertificate()&lt;/code&gt; we see the code required to open a socket to the remote site and prepare the context required to establish a secure connection.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# domain = &apos;example.com&apos;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# config[&apos;cafile&apos;] = &apos;/etc/ssl/certs/ca-certificates.crt&apos;&lt;/span&gt;
socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getaddrinfo&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;domain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
sock &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;socket&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AF_INET&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SOCK_STREAM&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;domain&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SSL&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SSL&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;TLSv1_METHOD&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token comment&quot;&gt;# prevent fallback to insecure SSLv2&lt;/span&gt;
ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;set_options&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SSL&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OP_NO_SSLv2 &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; SSL&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OP_NO_SSLv3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;set_verify&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SSL&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VERIFY_PEER &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; SSL&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VERIFY_FAIL_IF_NO_PEER_CERT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
               pyopenssl_check_callback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;load_verify_locations&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;cafile&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
ssl_sock &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SSL&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Connection&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
ssl_sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;set_connect_state&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
ssl_sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;set_tlsext_host_name&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;domain&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
ssl_sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;do_handshake&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that we are explicitly preventing the use of SSLv2, and we are asking pyOpenSSL to ensure we have a peer certificate. The &lt;code class=&quot;language-text&quot;&gt;pyopenssl_check_callback&lt;/code&gt; is used to ensure that any certificates present in the chain are not expired:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pyopenssl_check_callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;connection&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; x509&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; errnum&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; errdepth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&apos;&apos;&apos;callback for pyopenssl ssl check&apos;&apos;&apos;&lt;/span&gt;
    log&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;debug&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;callback: %d %s&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errdepth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; x509&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get_issuer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commonName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; x509&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;has_expired&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; CertificateError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Certificate %s has expired!&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; x509&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get_issuer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commonName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; ok&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ok&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we have an SSL context we can take a deeper look at the X.509 peer certificate. The code below calls &lt;code class=&quot;language-text&quot;&gt;match_hostname()&lt;/code&gt; to perform a rigorous check per &lt;a href=&quot;https://tools.ietf.org/html/rfc6125&quot;&gt;RFC 6125&lt;/a&gt; that the domain requested matches the different possible hostnames that can be found in a certificate and can be found within &lt;a href=&quot;https://github.com/bear/kenkou/blob/master/kenkou.py&quot;&gt;kenkou.py&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;x509 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ssl_sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get_peer_certificate&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    match_hostname&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x509&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; domain&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; CertificateError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Hostname does not match&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
expire_date &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; datetime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datetime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;strptime&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x509&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get_notAfter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%Y%m%d%H%M%SZ&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
expire_td   &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; expire_date &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; datetime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datetime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;now&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; expire_td&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;days &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Expires in %s days&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; expire_td&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;days&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can now feel confident that our certificate is valid. We can also now be warned/reminded when the certificate will be expiring. The ability to verify allows you be proactive instead of reactive, which is a much better way to walk the Operations path than constantly reacting to issues.&lt;/p&gt;
&lt;p&gt;Want more cool stuff like the Tao of Ops? Then sign up for our email list and have more good stuff delivered direct to your inbox. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Goodbye to And Bang. You were our friend.]]></title><description><![CDATA[Focus is hard, painful work.It's especially difficult to let go of things you really care about in order to focus on the things you care…]]></description><link>https://blog.andyet.com/2014/11/11/goodbye-andbang/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/11/goodbye-andbang/</guid><pubDate>Tue, 11 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Focus is hard, painful work.&lt;/p&gt;
&lt;p&gt;It&apos;s especially difficult to let go of things you really care about in order to focus on the things you care about &lt;em&gt;more&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But to keep our idealism, we need to grow up sometimes.&lt;/p&gt;
&lt;p&gt;We’ve decided to close And Bang so that we can put all our efforts into &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt;, &lt;a href=&quot;https://github.com/otalk&quot;&gt;Otalk&lt;/a&gt;, and our services (realtime &lt;a href=&quot;http://andyet.com/consulting&quot;&gt;consulting&lt;/a&gt; and &lt;a href=&quot;http://andyet.com/training&quot;&gt;training&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;And Bang was one of the first products we ever built and represents several years of effort by our team. I vividly remember finishing the And Bang 1.0 signup UI and landing page in a hotel room with &lt;a href=&quot;https://andyet.com/team/henrik&quot;&gt;Henrik&lt;/a&gt; the night before the first Keeping it Realtime Conference in &lt;a href=&quot;http://2011.realtimeconf.com/&quot;&gt;2011&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a company financially driven mostly by service revenue, it is very hard to invest heavily enough in both open source and products—and extremely hard when they go in different directions, technology-wise. Last May, we decided that we would not ship a paid version of And Bang, and would transition it to a new version of the product built on top of &lt;a href=&quot;http://otalk.org/&quot;&gt;Otalk&lt;/a&gt; before doing so.&lt;/p&gt;
&lt;p&gt;We aimed to keep And Bang alive, but we stopped development on it entirely, putting that energy into components of Otalk. But even keeping it in that state meant a certain amount of complexity, and some guilt over leaving it languishing.&lt;/p&gt;
&lt;p&gt;After some hard conversations this Fall, we decided to end the product entirely, close the servers in two weeks (November 21, 2014), and redirect our available energy into fewer, clearer channels of effort.&lt;/p&gt;
&lt;p&gt;We believe in the direction we’re going with Talky and Otalk. They really matter to us, and we believe they can help others, and fit into our vision.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Want to learn more about what we have coming up next? Then sign up for our email list!&lt;/em&gt;  &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing git-validate]]></title><description><![CDATA[Maintaining code quality is hard. That's why a little over two years ago, I created precommit-hook to help automate things like linting and…]]></description><link>https://blog.andyet.com/2014/11/10/gitvalidate/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/10/gitvalidate/</guid><pubDate>Mon, 10 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Maintaining code quality is hard. That&apos;s why a little over two years ago, I created &lt;a href=&quot;https://github.com/nlf/precommit-hook&quot;&gt;precommit-hook&lt;/a&gt; to help automate things like linting and running tests.&lt;/p&gt;
&lt;p&gt;Over the years, &lt;a href=&quot;https://github.com/nlf/precommit-hook&quot;&gt;precommit-hook&lt;/a&gt; has evolved, but it&apos;s always had the same basic functionality. Run a simple &lt;code class=&quot;language-text&quot;&gt;npm i --save-dev precommit-hook&lt;/code&gt; and the module takes care of the rest. It&apos;s worked great for a long time, and been adopted by quite a few people. So then what&apos;s the problem?&lt;/p&gt;
&lt;p&gt;Customization. If you want to change the behavior of the hook, you have to either fork it and make the changes yourself and publish a new module, or you have to make manual changes to your project&apos;s &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;. For a module with the goal of making things as simple as possible, that&apos;s kind of a bummer.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;https://github.com/nlf/git-validate&quot;&gt;git-validate&lt;/a&gt;. The idea behind git-validate isn&apos;t to automatically do all the things for you, but rather to provide a very simple framework for creating your own modules that do as much or as little as you want them to.&lt;/p&gt;
&lt;p&gt;Using git-validate, you essentially gain the ability to create a template for your projects. For an example of this, I have ported &lt;a href=&quot;https://github.com/nlf/precommit-hook&quot;&gt;precommit-hook&lt;/a&gt; to leverage &lt;a href=&quot;https://github.com/nlf/git-validate&quot;&gt;git-validate&lt;/a&gt; to give you an idea of how it will work. The &lt;a href=&quot;https://github.com/nlf/precommit-hook/blob/master/bin/install&quot;&gt;install file&lt;/a&gt; is where all the magic happens.&lt;/p&gt;
&lt;p&gt;No more assumptions are made about what linter you use, what scripts you want to run, or what files you want included in your project when the module is installed. You have absolute control. The &lt;code class=&quot;language-text&quot;&gt;pre-commit&lt;/code&gt; hook isn&apos;t even created unless &lt;em&gt;you&lt;/em&gt; create it. Have a script you want to run on &lt;code class=&quot;language-text&quot;&gt;pre-push&lt;/code&gt;? Go ahead! Add a &lt;code class=&quot;language-text&quot;&gt;Validate.installHooks(&amp;#39;pre-push&amp;#39;);&lt;/code&gt; to your module&apos;s install script, add the &lt;code class=&quot;language-text&quot;&gt;&amp;quot;pre-push&amp;quot;&lt;/code&gt; key to your &lt;code class=&quot;language-text&quot;&gt;.validate.json&lt;/code&gt; and you&apos;re done!&lt;/p&gt;
&lt;p&gt;With git-validate my hope is to see a ton of inventive new ways that people are maintaining their code quality. Create your own module and send me a link (I&apos;m &lt;a href=&quot;https://twitter.com/quitlahok&quot;&gt;@quitlahok&lt;/a&gt; on twitter); I&apos;d love to see what you&apos;re are doing with it.&lt;/p&gt;
&lt;p&gt;(&lt;em&gt;NOTE:&lt;/em&gt; as of the writing of this blog post, git-validate is at version 0.1.0. That means it&apos;s not completely finished. Linux and OS X support is functionally complete, but Windows support needs some work. If you use Windows, I would recommend waiting for the 1.0.0 release, which should be coming in the next few days.)&lt;/p&gt;
&lt;p&gt;Hey there! Want more cool stuff from the &amp;#x26;yet team? Then why not sign up for our mailing list? It&apos;s chock-full of vitamin G (for goodies). &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Today on DevCouch: What is Otalk?]]></title><description><![CDATA[What is Otalk? Jenna and Speegle sit down with Fritzy as he explains the secret sauce behind Otalk.But wait, there's more!Want to know more…]]></description><link>https://blog.andyet.com/2014/11/07/otalk-video/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/07/otalk-video/</guid><pubDate>Fri, 07 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;What is Otalk? &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://andyet.com/team/jenna&quot;&gt;Jenna&lt;/a&gt; and &lt;a href=&quot;https://andyet.com/team/mike&quot;&gt;Speegle&lt;/a&gt; sit down with &lt;a href=&quot;https://andyet.com/team/nathan&quot;&gt;Fritzy&lt;/a&gt; as he explains the secret sauce behind &lt;a href=&quot;https://otalk.org/&quot;&gt;Otalk&lt;/a&gt;.&lt;/p&gt;
&lt;iframe src=&quot;//player.vimeo.com/video/111242282&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt; &lt;p&gt;&lt;a href=&quot;http://vimeo.com/111242282&quot;&gt;Otalk&lt;/a&gt; from &lt;a href=&quot;http://vimeo.com/andyet&quot;&gt;&amp;amp;yet&lt;/a&gt; on &lt;a href=&quot;https://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;but-wait-theres-more&quot;&gt;&lt;a href=&quot;#but-wait-theres-more&quot; aria-label=&quot;but wait theres more permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But wait, there&apos;s more!&lt;/h2&gt;
&lt;p&gt;Want to know more about Otalk? What about the next release of Talky? Wanna get a bi-weekly dispatch of stuff we&apos;re learning and doing at &amp;#x26;yet? Join our community! We can&apos;t be &amp;#x26;yet without &amp;#x26;you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Efficient, consistent client-side apps with optimistic concurrency & JSON patch]]></title><description><![CDATA[While working on a line of business application for a client recently, I was asked to research and implement two different approaches…]]></description><link>https://blog.andyet.com/2014/11/06/optimistic-concurrency-and-json-patch/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/06/optimistic-concurrency-and-json-patch/</guid><pubDate>Thu, 06 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;While working on a line of business application for a client recently, I was asked to research and implement two different approaches towards improving data updating efficiency and consistency. &lt;/p&gt;
&lt;p&gt;The first is &lt;a href=&quot;http://tools.ietf.org/html/rfc6902&quot;&gt;JSON Patch&lt;/a&gt;. The idea here is to reduce data transfer by only sending the operations needed to make the remote resource identical to the local one. Even though both resources are represented as JSON objects, applying patches means we don&apos;t have to replace the entire entity on every update. This also reduces the risk of accidental changes to data that stays the same. &lt;/p&gt;
&lt;p&gt;The second is &lt;a href=&quot;https://en.wikipedia.org/wiki/Optimistic_concurrency_control&quot;&gt;optimistic concurrency control&lt;/a&gt;. This approach allows multiple users to open a data record for editing at the same time, and determines whether there are any conflicts at save time. &lt;/p&gt;
&lt;p&gt;Our working hypothesis was that combining these two approaches would enable us to build a more bandwidth-efficient, data-consistent application while also providing a more pleasant user experience.&lt;/p&gt;
&lt;h2 id=&quot;the-research&quot;&gt;&lt;a href=&quot;#the-research&quot; aria-label=&quot;the research permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Research&lt;/h2&gt;
&lt;p&gt;Given these new ideas, I wanted to get a basic understanding of the theory behind both, so I did some searching and reading.  Here&apos;s what I learned.&lt;/p&gt;
&lt;h2 id=&quot;a-bit-of-background-on-optimistic-concurrency-via-http&quot;&gt;&lt;a href=&quot;#a-bit-of-background-on-optimistic-concurrency-via-http&quot; aria-label=&quot;a bit of background on optimistic concurrency via http permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A bit of background on optimistic concurrency via HTTP&lt;/h2&gt;
&lt;p&gt;Pessimistic concurrency, the traditional approach to protecting data integrity, requires locking the data resource until the update is committed. Optimistic concurrency, on the other hand, does not lock the resource, preferring instead to check for violations of integrity rules just-in-time as the last step before committing. The pessimistic approach is best in situations where there is a high likelihood of conflicting edits because the lock is acquired and released regardless of any actual conflicts to be prevented, making it significantly slower in most cases than a non-locking approach. In situations where the likelihood of conflicts is low, the optimistic approach is faster because it only follows the slow path—a rolled-back transaction—in the event of an actual conflict.&lt;/p&gt;
&lt;p&gt;In our case, we would be using HTTP headers to pass the integrity check data for our optimistic concurrency system, so I started reading up on it. A quick Google search turned up a few useful resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://blogs.msdn.com/b/marcelolr/archive/2010/07/20/http-and-optimistic-concurrency.aspx&quot;&gt;Marcello Lopez Ruiz&apos;s brief post about using ETags and If-Match for optimistic concurrency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://fideloper.com/etags-and-optimistic-concurrency-control&quot;&gt;Chris Fidao&apos;s excellent, more in-depth write up: &lt;em&gt;ETags and Optimistic Concurrency Control&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Tudor Turcu&apos;s &lt;a href=&quot;http://tudorturcu.wordpress.com/2012/04/30/optimistic-concurrency-control-asp-net-webapi-en/&quot;&gt;writeup on &lt;em&gt;Optimistic concurrency control in ASP.NET WebAPI&lt;/em&gt;&lt;/a&gt; and &lt;a href=&quot;http://tudorturcu.wordpress.com/2012/05/17/optimistic-concurrency-support-in-http-and-webapi-part-2/&quot;&gt;a brief follow-up&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These articles all assume that you will be using &lt;a href=&quot;http://tools.ietf.org/html/rfc7232#section-2.3&quot;&gt;ETag&lt;/a&gt; and &lt;a href=&quot;http://tools.ietf.org/html/rfc7232#section-3.1&quot;&gt;If-Match&lt;/a&gt; for transporting version information, but the header field definitions in the official HTTP specs also discuss another pair for similar uses: &lt;a href=&quot;http://tools.ietf.org/html/rfc7232#section-2.2&quot;&gt;Last-Modified&lt;/a&gt; and &lt;a href=&quot;http://tools.ietf.org/html/rfc7232#section-3.4&quot;&gt;If-Unmodified-Since&lt;/a&gt;. Depending on the situation, either option may be appropriate. In the case of our app, Last-Modified was the path of least resistance because our REST API was already sending that header and the limited resolution of HTTP date was not likely to be an issue.&lt;/p&gt;
&lt;p&gt;To summarize, our server sends something like &lt;code class=&quot;language-text&quot;&gt;Last-Modified: Sun, 26 Sep 2010 22:04:35 GMT&lt;/code&gt; and our client app needs to store the value and send it back as &lt;code class=&quot;language-text&quot;&gt;If-Unmodified-Since: Sun, 26 Sep 2010 22:04:35 GMT&lt;/code&gt; when it sends updated data to the server. In addition, the client would need to handle a 412 error response from the server as an invalid version error, meaning that the If-Unmodified-Since check had failed.&lt;/p&gt;
&lt;h2 id=&quot;json-patch-basics&quot;&gt;&lt;a href=&quot;#json-patch-basics&quot; aria-label=&quot;json patch basics permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;JSON Patch basics&lt;/h2&gt;
&lt;p&gt;There are a number of operations that can be modeled via JSON Patch: add, remove, replace, copy, move, and test. Each operation is modeled using a specially formed JSON object. Every operation type has an &quot;op&quot; and a &quot;path&quot; property. The copy and move operation also have a &quot;from&quot; property. Finally, the add, replace, and test operations have &quot;value&quot; property. For our purposes, client-server communication is entirely modeled via add, replace and remove. Here are some examples of those operation objects:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; original &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;cars&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;De Ville&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Fleetwood&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; add &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/cars/2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Eldorado&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; remove &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;remove&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/cars/1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; replace &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/cars/0/model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Coupe De Ville&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// The result of applying the above would be:&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; patched &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;cars&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Coupe De Ville&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;El Dorado&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our client application would need to accumulate any changes to a model or its child models and collections as JSON Patch operations and send them to the server on save.&lt;/p&gt;
&lt;p&gt;The sites that helped me the most to understand JSON Patch were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc6902&quot;&gt;The RFC page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://jsonpatch.com/&quot;&gt;jsonpatch.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;prior-art-and-priorités-dart&quot;&gt;&lt;a href=&quot;#prior-art-and-priorit%C3%A9s-dart&quot; aria-label=&quot;prior art and priorités dart permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Prior Art and Priorités d&apos;Art&lt;/h2&gt;
&lt;p&gt;Armed with this new knowledge and ready to tackle implementation, I began by searching for previous Backbone implementations of these concepts. I saw that Backbone supported HTTP&apos;s PATCH verb, but it had no additional support for tracking what had changed since the last sync with the server. I found a &lt;a href=&quot;http://stackoverflow.com/questions/24879049/how-to-use-jsonpatch-with-backbonejs-nested-model&quot;&gt;Stack Overflow question&lt;/a&gt; and a &lt;a href=&quot;http://jsonpatchjs.com/&quot;&gt;jsonpatch library that mentioned Backbone&lt;/a&gt;, but no fully-baked generic solutions for JSON Patch. When I went looking for optimistic concurrency solutions, I couldn&apos;t even find a Stack Overflow question about it. Since I couldn&apos;t find any solutions, I&apos;d have to build my own from scratch.&lt;/p&gt;
&lt;p&gt;As I thought through my approach, I kept these things in mind:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It had to work both with Backbone and &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand&lt;/a&gt;, which we were planning to migrate to in the next few months.&lt;/li&gt;
&lt;li&gt;It should require minimal configuration from developers for most cases.&lt;/li&gt;
&lt;li&gt;It must be modular, allowing the use of optimistic concurrency without JSON Patch and vice versa.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In my next post, I&apos;ll describe how I went about implementing these solutions, and the operational results in the efficiency of updating data in our application.&lt;/p&gt;
&lt;p&gt;COMING SOON: &quot;Part II: Building the Mixins&quot;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Do you like reading fun stuff like this? Then why not sign up for our mailing list? Check it out below.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Tao of Ops: Monitoring infrastructure with active testing]]></title><description><![CDATA["If you don't monitor it, you can't manage it."That's a variation on the business management saying "you can't manage what you can't measure…]]></description><link>https://blog.andyet.com/2014/11/05/test-it-or-dont-trust-it/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/05/test-it-or-dont-trust-it/</guid><pubDate>Wed, 05 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&quot;If you don&apos;t monitor it, you can&apos;t manage it.&quot;&lt;/p&gt;
&lt;p&gt;That&apos;s a variation on the business management saying &quot;you can&apos;t manage what you can&apos;t measure&quot; (often attributed to Peter Drucker). The saying might not always apply to business, but it definitely applies to Operations.&lt;/p&gt;
&lt;p&gt;There are a lot of tools you can bring into your organization to help with monitoring your infrastructure, but they usually look at things only from the &quot;inside perspective&quot; of your own systems. To truly know if the path your Operations team is walking is sane, you need to also check on things from the user&apos;s point of view. Otherwise you are missing the best chance to fix something before it becomes a problem that leads your customers to take their business elsewhere.&lt;/p&gt;
&lt;p&gt;Active testing of your systems from the outside is crucial and something that is easy enough to set up. For each internal system you are monitoring, ask yourself how you would create a query or request from the outside using that internal system.&lt;/p&gt;
&lt;p&gt;A good example to start with is your web server. To actively test it you could make a curl request against the URL for your site and trigger an alert if it returns anything other than a &apos;&apos;200 OK&apos;&apos;&apos; response. This pattern can be followed for many services that are web facing. Make sure to include login pages, queries, and anything your customers use every day.&lt;/p&gt;
&lt;p&gt;Other checks to make include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNS entries&lt;/li&gt;
&lt;li&gt;TLS certificates&lt;/li&gt;
&lt;li&gt;Mixed content warnings for your pages&lt;/li&gt;
&lt;li&gt;Cloud service security settings (e.g., are your S3 buckets open to the public?)&lt;/li&gt;
&lt;li&gt;Firewall settings (e.g., are ports open for expired services?)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these should be worked into scripts that should be run on a regular basis, with any exceptions logged and alerted.&lt;/p&gt;
&lt;p&gt;We will be working through all of these examples in more detail with later blog posts, so watch this space for future installments.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Do you like reading fun stuff like the Tao of Ops? Then why not sign up for our mailing list? Details below.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Your code isn't the most important part of your project]]></title><description><![CDATA[When you think about a software project, and specifically the people that are involved with it, you probably think about developers.  After…]]></description><link>https://blog.andyet.com/2014/11/04/your-code-isnt-the-most-important/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/04/your-code-isnt-the-most-important/</guid><pubDate>Tue, 04 Nov 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When you think about a software project, and specifically the people that are involved with it, you probably think about developers.  After all, the code itself is what makes up the project.  I submit to you that we have a perception problem in the software world.  In fact I think we have it backwards.  The software is the least important thing in your software project.&lt;/p&gt;
&lt;p&gt;Currently, code commits get all the attention and metrics.  They are typically what a project will use to measure progress, complexity, and really anything that is considered &lt;em&gt;meaningful&lt;/em&gt; to the work as a whole.  The fact is though, they&apos;re the last thing anyone who uses your software actually sees.  It doesn&apos;t matter if you&apos;re writing client-side code, or a backend helper library: the first thing anyone will likely see, and the thing they will interact with the most is the documentation.&lt;/p&gt;
&lt;p&gt;In today&apos;s software ecosystem code is cheap.  Problems are relatively easily solved.  What language you choose and what approach you take can often be a matter of personal preference and style.  There are of course exceptions but these are far from the vast majority of situations.  What really matters is how quickly the code you write can be of usefulness to anyone else besides yourself.  Chances are you are not writing code in a vacuum (if you are, hello you have a weird setup and should probably join us in the 21st century, it&apos;s nice here).  Think about the last time you used any software at all.  Did you just intuitively know how to run it? No you had to read the documentation.  It&apos;s strange then that the first thing we see has become somehow so low in our priority list.&lt;/p&gt;
&lt;h2 id=&quot;visibility-is-important&quot;&gt;&lt;a href=&quot;#visibility-is-important&quot; aria-label=&quot;visibility is important permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Visibility is important&lt;/h2&gt;
&lt;p&gt;Now, I&apos;m not just saying these things because it&apos;s what I&apos;ve been doing lately. Ok yes that&apos;s exactly why I&apos;m saying it.  I&apos;ve been trying to keep up with all the super awesome documentation help people are giving us on &lt;a href=&quot;http://ampersandjs.com&quot;&gt;Ampersandjs&lt;/a&gt; and it has really made me realize how super important it is that the docs are right for everyone when they want to use that software.  We all in the back of our heads probably realize how important documentation is, but rarely do anything beyond paying meager lip service.  This is because visibility is important, it&apos;s only when you&apos;re knee-deep in it that you can appreciate something&apos;s importance.&lt;/p&gt;
&lt;p&gt;Documentation is hard, I don&apos;t think anyone would disagree with this. It&apos;s also not prioritized.  It goes way beyond just adding a few comments in your code (which I would argue is the opposite of documentation).  Part of the reason is because it&apos;s also not glamorous.  Nobody talks about how great a piece of software&apos;s documentation is (though I&apos;ll bet without solid documentation people rarely would describe any software as that great).&lt;/p&gt;
&lt;p&gt;Part of giving documentation visibility is also not over-emphasizing the code.  While it&apos;s easy and tempting to make your &apos;contributors&apos; page a list of commits to your version control, think: does this include the people who helped with testing, or documentation, or bug scrubbing?  Try to keep these things in mind when you&apos;re building your &apos;community&apos; and the pages that represent it.&lt;/p&gt;
&lt;h2 id=&quot;taking-action&quot;&gt;&lt;a href=&quot;#taking-action&quot; aria-label=&quot;taking action permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Taking action&lt;/h2&gt;
&lt;p&gt;So how can this be combatted?  I suggest dedicating someone to this task.   Acknowledge that it takes time and effort and that you consider this to be important.  Make documentation of paramount importance.  It will never &apos;organically&apos; happen.  It will take a conscious effort.&lt;/p&gt;
&lt;p&gt;Additionally, if you are doing open source give the most positive feedback to people helping with this area of your project.  Put up the fewest barriers to them.  Your docs likely don&apos;t need the same stringent rules before acceptance that perhaps your code does.  Maybe your one person in charge is authorized to scrub and accept all documentation updates.  Positive feedback and a great experience are two important ways to keep people engaged and willing to contribute.&lt;/p&gt;
&lt;p&gt;Find ways to acknowledge those who contribute in this way. Afford them the same status as anyone contributing code.  &lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;&lt;a href=&quot;#getting-started&quot; aria-label=&quot;getting started permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Looking for some place to start? I have a suggestion: documentation-driven-development.  If it&apos;s not documented, it doesn&apos;t exist.  This isn&apos;t a new thing it&apos;s the reality that already exists. If a person doesn&apos;t know how to use something in your software they can&apos;t use it.  Following this train of thought, make everything follow your documentation.  Integration tests now become documentation tests, they test what your documentation says is how things work.  This is by no means the only way to do it, but it is a great place to start if you need one.&lt;/p&gt;
&lt;h2 id=&quot;you-wont-be-going-alone&quot;&gt;&lt;a href=&quot;#you-wont-be-going-alone&quot; aria-label=&quot;you wont be going alone permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;You won&apos;t be going alone&lt;/h2&gt;
&lt;p&gt;I&apos;ve tried to find a few good examples of projects that are giving the people who help w/ documentation credit, and I know there are many others.&lt;/p&gt;
&lt;p&gt;On the &lt;a href=&quot;http://ampersandjs.com/contribute&quot;&gt;Ampersand&lt;/a&gt; contributors page, everyone is given equal representation whether they contributed readme updates, css tweaks, or actual code.  In fact I would like to take the opportunity to call out &lt;a href=&quot;https://twitter.com/remko&quot;&gt;@remko&lt;/a&gt; for creating an &lt;a href=&quot;https://github.com/remko/ampersandjs-dash-generator&quot;&gt;Ampersand dash docset&lt;/a&gt; that I use every day.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.drupal.org/contribute/documentation&quot;&gt;Drupal&lt;/a&gt; has a whole page/subcommunity dedicated to helping with documentation.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.djangoproject.com/en/1.7/internals/committers/&quot;&gt;Django&lt;/a&gt; puts documentation on the same level as code, and lists several people on their committers page as having documentation be their main area.&lt;/p&gt;
&lt;p&gt;Another good example is &lt;a href=&quot;http://symfony.com/contributors&quot;&gt;Symfony&lt;/a&gt; which has a specific area where people who helped with documentation are acknowledged.&lt;/p&gt;
&lt;p&gt;Do you know of projects that are doing documentation right?  Shout their praises to me on &lt;a href=&quot;https://twitter.com/wraithgar&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;p.s.
I am focusing on one facet of software but there are many, this post is intended as a focus on one of them not a distraction from others such as QA, support, bug scrubbing, education, ops, (I could go on), all of which are just as important as the rest.  The incorrect primacy we give developers in the software ecosystem is unwarranted and harmful to your own projects.  Let&apos;s work to change that.&lt;/p&gt;
&lt;p&gt;Want more like this (and also get a bi-weekly dispatch of stuff we&apos;re learning and doing at &amp;#x26;yet?) Join our community! We can&apos;t be &amp;#x26;yet without &amp;#x26;you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Pen + paper + punk rock productivity]]></title><description><![CDATA[The Green NotebookI stepped foot through the door as an official yeti almost exactly two months ago. I’ve changed jobs before, but somehow…]]></description><link>https://blog.andyet.com/2014/11/03/Pen-Paper-Punk-Rock-Productivity/</link><guid isPermaLink="false">https://blog.andyet.com/2014/11/03/Pen-Paper-Punk-Rock-Productivity/</guid><pubDate>Mon, 03 Nov 2014 13:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-green-notebook&quot;&gt;&lt;a href=&quot;#the-green-notebook&quot; aria-label=&quot;the green notebook permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Green Notebook&lt;/h2&gt;
&lt;p&gt;I stepped foot through the door as an official yeti almost exactly two months ago. I’ve changed jobs before, but somehow this time it felt a bit different. Sort of a cross between moving to a country where you don’t know the language, and walking into the cafeteria on your first day of 7th grade. While at the store purchasing a handful of requisite office items, I felt compelled to toss a little green notebook in the basket. I’m not sure why, but it just seemed necessary.&lt;/p&gt;
&lt;h2 id=&quot;socially-acceptable-security-blanket&quot;&gt;&lt;a href=&quot;#socially-acceptable-security-blanket&quot; aria-label=&quot;socially acceptable security blanket permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Socially Acceptable Security Blanket&lt;/h2&gt;
&lt;p&gt;My first few weeks on the job, I had a ton of conversations with a ton of other people. Yetis, by nature, tend to constantly burble ideas, and I didn’t want to miss any of it. Having made the transition from designer to front-end developer, and now to back-end developer, I was tasked with sponging new languages, terminologies, ways of thinking, processes, programs, and people. As a way of coping, I just cracked open that green notebook and started scribbling. I talked to people and scribbled, I worked on projects and scribbled, I read articles and scribbled…I scribbled myself off cliffs of anxiety, and I scribbled my way out of mental blocks. There were even times when I just clung to it and fiddled with the ribbon bookmark and elastic closure strap just to give my fidgety hands something to do while I made sense of what I was feeling. You could say that it was akin to a socially acceptable security blanket.&lt;/p&gt;
&lt;p&gt;Within a few weeks of constantly wielding the green notebook, my colleague and fellow yeti, Mike Speegle, commented on my use of good old fashioned pen and paper, and we had some serious bonding over this medium. For Mike, it seemed the appeal was in the tactility of the process of putting pen to paper, and finding just the right pen for the job. I’ll write with/on just about anything. For me it’s all about catching those ideas before they fly away.&lt;/p&gt;
&lt;h2 id=&quot;theres-not-an-app-for-that&quot;&gt;&lt;a href=&quot;#theres-not-an-app-for-that&quot; aria-label=&quot;theres not an app for that permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;There’s &lt;em&gt;not&lt;/em&gt; an app for that&lt;/h2&gt;
&lt;p&gt;You may be thinking, &quot;there&apos;s an app for that&quot;, and I do utilize several of these popular note-taking apps. But they all fall short for a few fundamental reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the time it takes to unlock your device, navigate to an app, and find/name a note, you’ve lost or talked yourself out of writing the really good ideas.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When you write on paper, there&apos;s no time wasted on formatting and hierarchy of ideas. As a designer, I cannot leave a &quot;wall of text&quot; as is. It&apos;s got to be organized formatted, and polished. Doing so can singularly kill an amazing train of thought. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There&apos;s something non-judgemental about paper. A piece of paper feels like a safer, more welcome, home to those random, fleeting thoughts that are mere glimmers of ideas. On paper, your thoughts can be vulnerable, controversial and undiluted. These are the thoughts we don&apos;t want to lose. That&apos;s where the truly good ideas hide.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When retrieving ideas out of the mess, you have to pass by other ideas that you wouldn’t necessarily encounter if you were doing a search query in an app program.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;punk-rock-productivity&quot;&gt;&lt;a href=&quot;#punk-rock-productivity&quot; aria-label=&quot;punk rock productivity permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Punk Rock Productivity&lt;/h2&gt;
&lt;p&gt;There’s this idea that productivity means accomplishing tasks as quickly and efficiently as humanly possible. &lt;strong&gt;But what if productivity means accomplishing a task with as much creativity, elegance, and ingenuity as possible?&lt;/strong&gt; I call this approach punk rock productivity. &lt;/p&gt;
&lt;p&gt;So grab a pen and write everything - absolutely everything - that spills out of your brain. There will be notes about things you need to pick up at the grocery store sandwiched between notes about mental breakthroughs you encounter while working on a project. Or quick bulleted lists of dev procedures scrawled alongside long, messy passages addressing the morning’s anxiety. &lt;/p&gt;
&lt;p&gt;Find some paper and write. Capture that constant flood of ideas about projects, ways of doing things, ways of thinking about things, and ways of seeing things. It may be chicken scratch, totally disorganized and out of order, but at least it&apos;s there. And that&apos;s the first step to making things happen, and not only accomplishing tasks, but understanding why you&apos;re doing them, and how to do them well. That, my friend, is true productivity.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Pitching the novel]]></title><description><![CDATA[For those of you playing along at home, you may have heard me mention the novel we here at &yet worked on this year, Something Greater than…]]></description><link>https://blog.andyet.com/2014/10/31/Pitching-the-Novel/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/31/Pitching-the-Novel/</guid><pubDate>Fri, 31 Oct 2014 13:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For those of you playing along at home, you may have heard me mention the novel we here at &amp;#x26;yet worked on this year, &lt;a href=&quot;http://www.amazon.com/Something-Greater-than-Artifice-Speegle-ebook/dp/B00FUF8X0Y&quot;&gt;Something Greater than Artifice&lt;/a&gt;, like a jillion times. For those of you who haven&apos;t: Hello! Welcome to the Internet. Please enjoy the heady melange of cultural experiences but for God&apos;s sake don&apos;t read the bottom half of anything. &lt;/p&gt;
&lt;p&gt;Anyway. &lt;a href=&quot;http://www.amazon.com/Something-Greater-than-Artifice-Speegle-ebook/dp/B00FUF8X0Y&quot;&gt;Something Greater than Artifice&lt;/a&gt; (or SGtA for you TL;DR folks). If you don&apos;t know the story behind it I&apos;m sure it&apos;s floating around &lt;a href=&quot;http://realtimeconf.com&quot;&gt;somewhere&lt;/a&gt; (subtle hint: that link takes you to the RealtimeConf site, which is both cool and awesome). Main thing is that I wrote a pretty good book and a bunch of cool people helped me turn it into a pretty very good book. Because without Amy illustrating and Jenn editing and Adam occasionally saying &quot;that part with the thing doesn&apos;t make sense&quot; this thing would be not as pretty very good as it is.&lt;/p&gt;
&lt;p&gt;Okay, fine. More than pretty very good. Doubleplus pretty very good. Because–if you&apos;ll abide a moment of hubris–the book was actually selected as the &lt;a href=&quot;https://www.kirkusreviews.com/lists/kirkus-indie-books-month-september-2014/something-greater-than-artifice/#feature&quot;&gt;Kirkus Reviews&lt;/a&gt; Indie Book of the Month Selection (caps theirs). Which got us to thinking that maybe, just maybe, we could take this thing which started as a conversation between Adam, Amy, and I and turn it into something greater. &lt;/p&gt;
&lt;p&gt;So we decided to get the dang thing published. &lt;/p&gt;
&lt;p&gt;(And you thought all we did here was make awesome codes. Ha and ha.)&lt;/p&gt;
&lt;p&gt;But to get published, you kind of need to follow...The Process. &lt;/p&gt;
&lt;h2 id=&quot;the-process&quot;&gt;&lt;a href=&quot;#the-process&quot; aria-label=&quot;the process permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Process&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Write an entire book&lt;/li&gt;
&lt;li&gt;Edit it a bunch&lt;/li&gt;
&lt;li&gt;Send a query to a bunch of literary agents   &lt;/li&gt;
&lt;li&gt;Do this for maybe ten years&lt;/li&gt;
&lt;li&gt;If the agent is interested, they might request a sample (turn time 4-8 weeks)&lt;/li&gt;
&lt;li&gt;If they’re very very interested they might request the full manuscript (turn time 1-6 months)&lt;/li&gt;
&lt;li&gt;If they decide to represent you, they will send a contract giving them 15% of your total book earnings (20% international (usually))&lt;/li&gt;
&lt;li&gt;The agent will then shop the book to editors at publishing houses (i.e. Penguin, Random House, Macmillan)&lt;/li&gt;
&lt;li&gt;If the editor is interested, they will read the book (turn time ???)&lt;/li&gt;
&lt;li&gt;If they agree to publish the book, they will provide the author with an advance (anywhere between $3k and $300k) based upon projected sales. No matter how the book does, the author does not have to pay this back (&quot;Woo hoo! Free ampersands for EVERYBODY!&quot;).&lt;/li&gt;
&lt;li&gt;The book goes through the editing process (turn time up to three billion years or longer)&lt;/li&gt;
&lt;li&gt;The book goes on sale&lt;/li&gt;
&lt;li&gt;A small percentage each book’s sale price (royalty) is used to make the up the difference in the advance. After the advance is “paid off,” the author begins receiving royalty payments. Most books do not make enough to pay back their royalty (but the ones that do make up for the rest of them)&lt;/li&gt;
&lt;li&gt;The author can then write another book and take it directly to his agent, who will more than likely help them turn it into something salable, thus short-circuiting the process (steps 1, 2, 7-13)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So: first an agent, which is a trick in itself. Some authors go their entire careers without landing one of these beautiful, legendary creatures. &lt;/p&gt;
&lt;p&gt;Lucky for me, the first nibble came this summer, when I was interrogating a fellow author on how she acquired her agent. As we sipped beers in the too-hot Vegas twilight, she explained to me that she met her rep during a literary conference.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hey Mike,&lt;/em&gt; my internal narrator said to me.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;What?&lt;/em&gt; I asked.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You know that’s like the fifth person to tell you that, right?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The revelation was like a fat desert moth to the face–shocking but not particularly painful. She was the fifth in a series of indie authors–nobodies like me–who met their agents and pried their way through those oft-sealed doors via the expedient of going places and meeting people.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A-doy,&lt;/em&gt; my internal narrator added.&lt;/p&gt;
&lt;p&gt;SO. The &lt;a href=&quot;http://newyorkpitchconference.com&quot;&gt;Algonkian NY Pitch Conference&lt;/a&gt;. Four days, four editors from major publishing houses, listening directly to me as I lobbed my best work at ‘em. &lt;/p&gt;
&lt;h2 id=&quot;the-new-process-as-dictated-by-old-man-circumstance&quot;&gt;&lt;a href=&quot;#the-new-process-as-dictated-by-old-man-circumstance&quot; aria-label=&quot;the new process as dictated by old man circumstance permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The NEW Process (As Dictated by Old Man Circumstance)&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Write a book with friends&lt;/li&gt;
&lt;li&gt;Edit and edit and edit and eat every bacon and edit and cry&lt;/li&gt;
&lt;li&gt;Get some book reviews&lt;/li&gt;
&lt;li&gt;Meet some editors, get them interested in the book&lt;/li&gt;
&lt;li&gt;Send queries to agents, letting them know that I already have editors on the hook, and that all they need to do is broker the deal for me&lt;/li&gt;
&lt;li&gt;Profit?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And with &amp;#x26;yet footing the bill and sending me on with their love, I had just enough chutzpah to believe in that sweet sweet heady sweet dream of traditional publication. &lt;/p&gt;
&lt;p&gt;I had a grip of resolutions when I arrived in NY, promising myself to write about my experiences every day, but I gotta tell ya, friends, there hasn’t been a single day this week when I didn’t walk back to my hotel, open my laptop, and then proceed to work on SGtA for another few (ha, “few”) hours.&lt;/p&gt;
&lt;p&gt;You know, SGtA, the book we already published.&lt;/p&gt;
&lt;p&gt;Because (and spoiler alert if you’ve never written a book or written a book well), writing is rewriting is rewriting is rewriting.&lt;/p&gt;
&lt;p&gt;Is rewriting.&lt;/p&gt;
&lt;h2 id=&quot;so&quot;&gt;&lt;a href=&quot;#so&quot; aria-label=&quot;so permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So.&lt;/h2&gt;
&lt;p&gt;Brushing up on the novel. Removing about a half-jillion instances of the word “was,” since it has somehow been breeding exponentially in the interstitial period between Ago and Now. Punching up the language even more.&lt;/p&gt;
&lt;p&gt;But most importantly: refining my pitch. Which–when you get right down to it–is just a query letter (which is itself a HUGE weak point for me). Just 200 words–less than a minute–to convince some of the biggest names in publishing that my book is worth the electrons it&apos;s printed on. &lt;/p&gt;
&lt;p&gt;It was to be my biggest challenge to date.&lt;/p&gt;
&lt;p&gt;More soon. &lt;/p&gt;
&lt;p&gt;P.S. Do you like literature? What about adventure? How about books where cello-wielding heroines kick all the asses and save all the days? Well then head over to &lt;a href=&quot;http://www.amazon.com/Something-Greater-than-Artifice-Speegle-ebook/dp/B00FUF8X0Y&quot;&gt;Amazon&lt;/a&gt; or &lt;a href=&quot;http://www.0s-1s.com/shelves/something-greater-than-artifice&quot;&gt;0s&amp;#x26;1s&lt;/a&gt; and pick up your very own copy of Something Greater than Artifice! I literally (figuratively) guarantee you&apos;ll love it. &lt;/p&gt;
&lt;p&gt;P.P.S. Do you like reading fun stuff like this? Howzabout getting regular updates on the goings-on around &amp;#x26;yet international headquarters? Of course you do! &quot;But how?&quot; you ask, all eager anticipation. &quot;Shhhh,&quot; I say. &quot;Don&apos;t worry, friend. There&apos;s a mailing list where you get get all the fun &lt;em&gt;delivered to your very own inbox.&lt;/em&gt;&quot; Check it out below!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[XMPP is even more wonderful with WebSocket]]></title><description><![CDATA[Way back in 2008, my friend Jack Moffitt wrote a blog post entitled XMPP Is Better With BOSH. In those ancient days of long polling, BOSH…]]></description><link>https://blog.andyet.com/2014/10/30/websocket/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/30/websocket/</guid><pubDate>Thu, 30 Oct 2014 18:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Way back in 2008, my friend &lt;a href=&quot;http://metajack.im/&quot;&gt;Jack Moffitt&lt;/a&gt; wrote a blog post entitled &lt;a href=&quot;http://metajack.im/2008/07/02/xmpp-is-better-with-bosh/&quot;&gt;XMPP Is Better With BOSH&lt;/a&gt;. In those ancient days of long polling, &lt;a href=&quot;http://xmpp.org/extensions/xep-0124&quot;&gt;BOSH&lt;/a&gt; was the state of the art for sending XMPP traffic over an HTTP transport because we needed something like the &lt;a href=&quot;https://en.wikipedia.org/wiki/Comet_%28programming%29&quot;&gt;Comet model&lt;/a&gt; for bidirectional communication over HTTP. Even at the time, we knew it was an ugly and temporary hack to send multiple HTTP request-response pairs via long polling, but we didn&apos;t have anything better. &lt;/p&gt;
&lt;p&gt;Since then, bidirectional communication between web browser and web service has come a long way, thanks to &lt;a href=&quot;http://tools.ietf.org/html/rfc6455&quot;&gt;WebSocket&lt;/a&gt;. Nowadays, you start with an HTTP connection but use the HTTP UPGRADE method to bootstrap directly into a long-lived bidirectional session (for this reason, WebSocket has been likened to &quot;TCP for the web&quot;). WebSocket has its warts too, but compared to BOSH it significantly reduces the overhead of maintaining HTTP-based connections for XMPP. Even better, it has become a truly standard foundation for building real-time web apps, with support in all the modern languages and frameworks for web development.&lt;/p&gt;
&lt;p&gt;The benefits of communicating XMPP over WebSocket encompass and extend the ones that Jack enumerated years ago for BOSH:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Greater resilience in the face of unreliable networks — here WebSocket does pretty much what BOSH and other &quot;Comet&quot; approaches did 10 years ago, but in a more network-friendly way by removing the need for long polling.&lt;/li&gt;
&lt;li&gt;The ability to recover from data loss — the BOSH model of recovering from network outages and communication glitches was generalized with the XMPP &lt;a href=&quot;http://xmpp.org/extensions/xep-0198.html&quot;&gt;stream management&lt;/a&gt; extension, this can be used with XMPP over WebSocket, too.&lt;/li&gt;
&lt;li&gt;Compression for free — well, it turns out that the free compression we got by sending XMPP over HTTP wasn&apos;t so free after all (cf. the CRIME and BREACH attacks), but there&apos;s a &lt;a href=&quot;http://datatracker.ietf.org/doc/draft-ietf-hybi-permessage-compression/&quot;&gt;native compression scheme&lt;/a&gt; for WebSocket which so far appears to avoid the security problems that emerged with application-layer compression in HTTP.&lt;/li&gt;
&lt;li&gt;Firewall friendliness — in this case WebSocket isn&apos;t quite as network-agnostic as BOSH, since it&apos;s known that some mobile networks especially prevent WebSocket from working well (usually because they don&apos;t handle the HTTP UPGRADE mechanism very well). Hopefully that will improve over time, but in the meantime we can always fall back to BOSH if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks in large measure to the dedication of yeti &lt;a href=&quot;https://andyet.com/team/lance&quot;&gt;Lance Stout&lt;/a&gt; and key contributions from Jack as well as Eric Cestari, the XMPP over WebSocket spec has just been published as &lt;a href=&quot;https://datatracker.ietf.org/doc/rfc7395/&quot;&gt;RFC 7395&lt;/a&gt;. This technology is a big factor in our long-term efforts to help XMPP love the web, and we&apos;re already using it extensively in the &lt;a href=&quot;https://blog.andyet.com/2014/10/22/Talky-2-is-Coming&quot;&gt;next generation&lt;/a&gt; of &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt;, in &lt;a href=&quot;https://github.com/otalk/stanza.io&quot;&gt;stanza.io&lt;/a&gt;, and more generally in the &lt;a href=&quot;https://otalk.org/&quot;&gt;Otalk platform&lt;/a&gt; we&apos;re building as a more open foundation for realtime communications.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Optimize for change. It’s the only constant.]]></title><description><![CDATA[There’s a bit of a kerfuffle right now in Angular.js land because, lo and behold, the 2.0 release contains drastic differences and there isn…]]></description><link>https://blog.andyet.com/2014/10/30/optimize-for-change-its-the-only-constant/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/30/optimize-for-change-its-the-only-constant/</guid><pubDate>Thu, 30 Oct 2014 15:36:00 GMT</pubDate><content:encoded>&lt;p&gt;There’s a bit of a kerfuffle right now in Angular.js land because, lo and behold, the 2.0 release contains &lt;a href=&quot;http://jaxenter.com/angular-2-0-112094.html&quot;&gt;drastic differences&lt;/a&gt; and there isn’t really an upgrade path. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you want to upgrade you&apos;ll likely need to completely re-write your app!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The structural updates they&apos;re proposing all sound like good improvements, but if you built a large app on 1.x and want to upgrade it doesn&apos;t really seem like you&apos;ll be able to use much of your code.&lt;/p&gt;
&lt;h2 id=&quot;losing-your-religion&quot;&gt;&lt;a href=&quot;#losing-your-religion&quot; aria-label=&quot;losing your religion permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Losing your religion&lt;/h2&gt;
&lt;p&gt;Ok, so what should you do? Pick another framework? &lt;/p&gt;
&lt;p&gt;As developers we seem to have a tendency to get really religious about frameworks. We invest a bunch of time learning a tool and then hold onto it tightly.&lt;/p&gt;
&lt;p&gt;But, it doesn&apos;t really buy us anything to be religious about tools. Simply converting to another big framework doesn&apos;t protect us from a similar situation in the future, does it?&lt;/p&gt;
&lt;h2 id=&quot;why-dont-we-anticipate-that-things-will-change-from-the-start&quot;&gt;&lt;a href=&quot;#why-dont-we-anticipate-that-things-will-change-from-the-start&quot; aria-label=&quot;why dont we anticipate that things will change from the start permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why don’t we anticipate that things will change from the start?&lt;/h2&gt;
&lt;p&gt;Change is the only constant. How can we optimize for change?&lt;/p&gt;
&lt;p&gt;Well, how do we deal with change in other large systems? &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;By not building large systems, but instead composing many small, independent things into a large system.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As it turns out, we’ve gotten to the point where clientside JavaScript apps &lt;strong&gt;are large systems&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Refactoring, rewriting, and rebuilding from scratch is expensive. Buying into a single framework is risky. On the other hand, not leveraging anybody else’s efforts and solved problems is wasteful and painful. So what do we do?&lt;/p&gt;
&lt;p&gt;The biggest takeaway I’ve had from building stuff with &lt;a href=&quot;http://nodejs.org/&quot;&gt;Node&lt;/a&gt; for the last four years is to build your code as small, focused, re-usable modules. &lt;/p&gt;
&lt;p&gt;This type of architecture lets us change a leaky faucet without having to &lt;em&gt;burn the whole building down&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We can apply these same approaches in our clientside apps. This means we can mix and match and install solutions to the specific problems that we’re facing.&lt;/p&gt;
&lt;p&gt;We’re doing that with &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt;. But I’ll let you in on a little secret:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ampersand isn’t actually a thing–it’s a bunch of &lt;em&gt;little&lt;/em&gt; things.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The only reason we gave it a shared name is so we can talk about is as a thing. But it’s really a loose collection of a bunch of optional modules. In fact, we call it &quot;Ampersand.js&quot;. But good luck finding a file to use by that name, it doesn’t exist!&lt;/p&gt;
&lt;p&gt;If you want something to model and fetch data from your API, but then use &lt;a href=&quot;http://facebook.github.io/react/&quot;&gt;React&lt;/a&gt; for your views, go for it. Just use &lt;a href=&quot;http://ampersandjs.com/docs#ampersand-rest-collection&quot;&gt;ampersand-rest-collection&lt;/a&gt; and &lt;a href=&quot;http://ampersandjs.com/docs#ampersand-model&quot;&gt;ampersand-model&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Need something smart to manage state while tracking touch events in your multi-touch library? Use &lt;a href=&quot;http://ampersandjs.com/docs#ampersand-state&quot;&gt;ampersand-state&lt;/a&gt; by itself.&lt;/p&gt;
&lt;p&gt;Just need something to manage clientside routing? Use &lt;a href=&quot;http://ampersandjs.com/docs#ampersand-router&quot;&gt;the router&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And we don’t just mix it with our own modules, we grab all sorts of other useful stuff from &lt;a href=&quot;http://npmjs.org/&quot;&gt;npm&lt;/a&gt;. We keep a small collection of a our favorites on &lt;a href=&quot;http://tools.ampersandjs.com/&quot;&gt;the tools site&lt;/a&gt;, but that’s just like a bookmark directory. There are a whole slew of tools available for clientside apps on npm. &lt;/p&gt;
&lt;p&gt;Tools like Angular and Ember require that you go &quot;all in&quot;. &lt;/p&gt;
&lt;p&gt;As a leader on a dev team, I personally consider it too risky to invest our team’s energy in learning the intricacies of a particular framework; I want our team to learn how to solve problems in JavaScript by combining the right tools for the job.
At the end of day, tools are just tools. Find and use what works best for you and your team. I just urge you to consider architectures that mitigate risk of marriage to a particular framework.&lt;/p&gt;
&lt;p&gt;No two apps are the same, so we optimize for change. It’s the only constant.&lt;/p&gt;
&lt;h2 id=&quot;references-and-further-reading&quot;&gt;&lt;a href=&quot;#references-and-further-reading&quot; aria-label=&quot;references and further reading permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;References and further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://ampersandjs.com&quot;&gt;Ampersand.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;My book, &lt;a href=&quot;http://humanjavascript.com&quot;&gt;Human Javascript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://jaxenter.com/angular-2-0-112094.html&quot;&gt;sneak peak at angular 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.reddit.com/r/programming/comments/2kl88s/angular_20_drastically_different/&quot;&gt;Reddit reactions to &quot;drastically different&quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/ryanflorence/status/527499008936525824&quot;&gt;this whole twitter thread is gold&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.andyet.com/2014/08/13/opinionated-rundown-of-js-frameworks&quot;&gt;My Opinionated Rundown of JS Frameworks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;wed-love-to-help&quot;&gt;&lt;a href=&quot;#wed-love-to-help&quot; aria-label=&quot;wed love to help permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;We’d love to help&lt;/h2&gt;
&lt;p&gt;If you’re looking for help moving from an &quot;all in&quot; toolkit like Angular to a completely composable approach, optimized for change, &lt;a href=&quot;mailto:contact@andyet.com&quot;&gt;let’s talk&lt;/a&gt;. &amp;#x26;yet provides advanced JS training and consulting to teams all over the world.&lt;/p&gt;
&lt;p&gt;See our client Glenn Scott’s recent &lt;a href=&quot;http://blog.andyet.com/2014/10/28/glenn-scott-on-how-caa-builds-apps&quot;&gt;Node Road talk&lt;/a&gt; as a good example of how we work to make JavaScript apps maintainable and fun to work on, while capable of evolving over the long run.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;P.S. I&apos;d love to hear your feedback on twitter &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;edited 10/29/2014 23:45pm&lt;/strong&gt;: The first version of this post was excessively critical of Angular. Angular is incredibly popular and growing like crazy. It&apos;s a brilliant, powerful framework that makes it easy to get started and really empowers developers. I disagree with some of the technical choices that have been made in the project, but that doesn&apos;t negate the fact is there are some really awesome people working on Angular. I respect them and their work very much. The engineering chops and dedication required to build a framework like Angular is inspiring. I was given frank feedback about the harshness of the original version of this post and I&apos;d like to genuinely apologize to the Angular team.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing our new WebRTC offerings: an easier way to get &yet on your team]]></title><description><![CDATA[Our general approach to consulting at &yet goes something like this: If we have a knack for something and we think it can help make you…]]></description><link>https://blog.andyet.com/2014/10/29/new-web-rtc-offerings/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/29/new-web-rtc-offerings/</guid><pubDate>Wed, 29 Oct 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Our general approach to consulting at &amp;#x26;yet goes something like this: If we have a knack for something and we think it can help make you better at what you do, help your team eliminate risk, or move more confidently down the right path, we &lt;em&gt;should&lt;/em&gt; do it. &lt;strong&gt;Starting today, we&apos;re offering &lt;a href=&quot;https://andyet.com/consulting/webrtc&quot;&gt;3 new WebRTC consulting packages&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In addition to building &lt;a href=&quot;https://talky.io/&quot;&gt;products&lt;/a&gt; and &lt;a href=&quot;https://otalk.org/&quot;&gt;open source software&lt;/a&gt;, our team has offered consulting services as long as we&apos;ve been a company. But now we&apos;ve started focusing in on how to better package the skills and expertise our community (that&apos;s you!) needs.&lt;/p&gt;
&lt;p&gt;After reaching out to and talking with teams actively working with WebRTC, we&apos;re hearing a lot of the same questions that need answering. Questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What open source tools are out there and where should we go to get started with them?&lt;/li&gt;
&lt;li&gt;How do we configure TURN/STUN servers so our WebRTC service can work consistently across firewalls?&lt;/li&gt;
&lt;li&gt;What is the best way to go about implementing WebRTC on iOS?&lt;/li&gt;
&lt;li&gt;How can we ensure we&apos;re providing a secure and private service? (Including HIPAA-compliance)&lt;/li&gt;
&lt;li&gt;Is it possible to build and scale a WebRTC service on our own infrastructure?&lt;/li&gt;
&lt;li&gt;How can we scale beyond a couple people in a group conversation?&lt;/li&gt;
&lt;li&gt;How could we add chat or whiteboarding alongside our video solution?&lt;/li&gt;
&lt;li&gt;How would we create a massive broadcast live video service?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whether you&apos;re looking for advice from WebRTC experts who have &lt;em&gt;been there, done that&lt;/em&gt; OR you want to team up with a well-rounded, resourceful consultancy to help drive a new chat or video feature or product forward, you&apos;ll find what you need with our team.&lt;/p&gt;
&lt;p&gt;Here&apos;s our new WebRTC consulting packages, available starting today:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://andyet.com/consulting/webrtc#starter&quot;&gt;The Starter Discussion&lt;/a&gt;: We&apos;ll tackle the tip of iceberg &lt;em&gt;with&lt;/em&gt; you.&lt;/strong&gt; Our WebRTC experts will provide high-level feedback and recommendations to your team. Read more about the Starter Discussion &lt;a href=&quot;https://andyet.com/consulting/webrtc#starter&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://andyet.com/consulting/webrtc#perfect-fit&quot;&gt;The Perfect Fit&lt;/a&gt;: If you&apos;re running up against a WebRTC wall, having likely met the same wall in our collective pasts, we can help your team navigate its way to safety and success.&lt;/strong&gt; We&apos;ll deliver and document plans and recommendations for your team with the option of custom feature development and design. Read more about the Perfect Fit &lt;a href=&quot;https://andyet.com/consulting/webrtc#perfect-fit&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://andyet.com/consulting/webrtc#monthly-retainer&quot;&gt;The Monthly Retainer&lt;/a&gt;: A high-touch approach to keeping &amp;#x26;yet on-board.&lt;/strong&gt; We&apos;ll lead weekly standups, deliver thorough code reviews and spec documentation and planning, and train your team on deploying and maintaining your new project. Oh! And this package includes a full week of design consulting, too. Read more about the Monthly Retainer &lt;a href=&quot;https://andyet.com/consulting/webrtc#monthly-retainer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;If you&apos;re looking for a little less or a little more, we can create a package to fit your needs. Just &lt;a href=&quot;mailto:contact@andyet.com&quot;&gt;get in touch&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Glenn Scott: How we build apps at CAA with Node and Ampersand.js]]></title><description><![CDATA[For the past year and a half, it's been our pleasure and privilege to serve CAA, an agency representing many of the most successful…]]></description><link>https://blog.andyet.com/2014/10/28/glenn-scott-on-how-caa-builds-apps/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/28/glenn-scott-on-how-caa-builds-apps/</guid><pubDate>Tue, 28 Oct 2014 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For the past year and a half, it&apos;s been our pleasure and privilege to serve &lt;a href=&quot;http://caa.com&quot;&gt;CAA&lt;/a&gt;, an agency representing many of the most successful professionals in film, television, music, sports, and theater.&lt;/p&gt;
&lt;p&gt;Glenn Scott leads the team there. Over the past few years, they&apos;ve transitioned their IT to building custom applications in Node. We&apos;re proud to say we&apos;ve been able to partner with Glenn&apos;s great team at CAA, playing a key role in their work during that time.&lt;/p&gt;
&lt;p&gt;Recently, Glenn gave a nice presentation as part of &lt;a href=&quot;http://www.joyent.com/noderoad&quot;&gt;Joyent&apos;s Node on the Road series&lt;/a&gt;. In it, he described the way CAA builds applications.&lt;/p&gt;
&lt;p&gt;Glenn talks about the challenge of maintenance in traditional IT and how building Node and JS web apps make that much less painful.&lt;/p&gt;
&lt;p&gt;His keys:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a platform where it&apos;s easy to create many small apps, where the mean time to business value is measured in days and weeks.&lt;/li&gt;
&lt;li&gt;Make it fun and glamorous to add features to shipped products.&lt;/li&gt;
&lt;li&gt;Make it easy to keep products modern, giving each layer an evolution pattern that allows parallel and independent updating of components.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Node and &lt;a href=&quot;http://ampersandjs.com&quot;&gt;Ampersand&lt;/a&gt;&apos;s mutual modularity make all these good things possible.&lt;/p&gt;
&lt;p&gt;For more, check out &lt;a href=&quot;https://www.joyent.com/developers/videos/node-js-on-the-road-la-glenn-scott&quot;&gt;Glenn&apos;s talk&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[CSSConf EU Keynote: Karolina Szczur on creativity and imposter syndrome]]></title><description><![CDATA[Karolina shared a thoroughly researched and powerful closing keynote at CSSConf EU last month titled, Validate Me. Imposter Syndrome is…]]></description><link>https://blog.andyet.com/2014/10/27/karolina-on-imposter-syndrome/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/27/karolina-on-imposter-syndrome/</guid><pubDate>Mon, 27 Oct 2014 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Karolina shared a thoroughly researched and powerful closing keynote at CSSConf EU last month titled, &lt;em&gt;Validate Me&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;Imposter Syndrome is something we talk about a lot around our team at &amp;#x26;yet.&lt;/p&gt;
&lt;p&gt;This is definitely a must-watch if you, like many of us, struggle with self-doubt.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot;
src=&quot;//www.youtube.com/embed/ZlxpF9taprI&quot; frameborder=&quot;0&quot;
allowfullscreen&gt;&lt;/iframe&gt;</content:encoded></item><item><title><![CDATA[Jenna & Speegle Explain it All: What is Talky?]]></title><description><![CDATA[What is Talky? Jenna and Speegle explain it all.With apologies to Clarissa. #sorrynotsorryBut wait, there's more!Want to be the first to…]]></description><link>https://blog.andyet.com/2014/10/24/talky-jenna-and-speegle-explain-it-all/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/24/talky-jenna-and-speegle-explain-it-all/</guid><pubDate>Fri, 24 Oct 2014 19:23:00 GMT</pubDate><content:encoded>&lt;p&gt;What is Talky? &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/jennatormanen&quot;&gt;Jenna&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/mike_speegle&quot;&gt;Speegle&lt;/a&gt; explain it all.&lt;/p&gt;
&lt;p&gt;With apologies to Clarissa. #sorrynotsorry&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/gLW9zK1QZkk&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;but-wait-theres-more&quot;&gt;&lt;a href=&quot;#but-wait-theres-more&quot; aria-label=&quot;but wait theres more permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But wait, there&apos;s more!&lt;/h2&gt;
&lt;p&gt;Want to be the first to know when the next release of Talky is ready? (And also get a bi-weekly dispatch of stuff we&apos;re learning and doing at &amp;#x26;yet?) Join our community! We can&apos;t be &amp;#x26;yet without &amp;#x26;you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Talky 2 is coming; a word about Otalk]]></title><description><![CDATA[We’ve been hard at work on the next generation of Talky for months and we're getting close.We think Talky 2 is going to help make group…]]></description><link>https://blog.andyet.com/2014/10/22/Talky-2-is-Coming/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/22/Talky-2-is-Coming/</guid><pubDate>Wed, 22 Oct 2014 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’ve been hard at work on the next generation of &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; for months and we&apos;re getting close.&lt;/p&gt;
&lt;p&gt;We think Talky 2 is going to help make group meetings better and simpler.&lt;/p&gt;
&lt;h2 id=&quot;whats-new-in-talky-2&quot;&gt;&lt;a href=&quot;#whats-new-in-talky-2&quot; aria-label=&quot;whats new in talky 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What&apos;s new in Talky 2?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;HD video group conversations with 25+ people&lt;/li&gt;
&lt;li&gt;text chat&lt;/li&gt;
&lt;li&gt;audio-only modes&lt;/li&gt;
&lt;li&gt;low-bandwidth modes&lt;/li&gt;
&lt;li&gt;dramatically improved UX&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;…and more.&lt;/p&gt;
&lt;h2 id=&quot;why-we-care&quot;&gt;&lt;a href=&quot;#why-we-care&quot; aria-label=&quot;why we care permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why we care&lt;/h2&gt;
&lt;p&gt;As a distributed team, there are very few conversations we have that don’t involve a Talky session. &lt;/p&gt;
&lt;p&gt;It’s as core to our work as any other piece of software in our belt, so we’re motivated to make it the best we possibly can.&lt;/p&gt;
&lt;p&gt;In fact, we’re so eager to solve this problem that we’ve pointed our entire focus as a company into this area.&lt;/p&gt;
&lt;h2 id=&quot;were-proud-of-the-team-working-on-talky-2&quot;&gt;&lt;a href=&quot;#were-proud-of-the-team-working-on-talky-2&quot; aria-label=&quot;were proud of the team working on talky 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;We’re proud of the team working on Talky 2.&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://andyet.com/team/karolina&quot;&gt;Karolina Szczur&lt;/a&gt; and &lt;a href=&quot;https://andyet.com/team/phil&quot;&gt;Philip Roberts&lt;/a&gt; are creating an all-new interface we think you’ll enjoy.&lt;/p&gt;
&lt;p&gt;Meanwhile, &lt;a href=&quot;https://andyet.com/team/lance&quot;&gt;Lance Stout&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/fippo&quot;&gt;Philipp Hancke&lt;/a&gt;, and &lt;a href=&quot;https://andyet.com/team/peter&quot;&gt;Peter Saint-Andre&lt;/a&gt; (in collaboration with the &lt;a href=&quot;https://jitsi.org/&quot;&gt;Jitsi team&lt;/a&gt; among others) are pushing forward some tried-and-true approaches and forging new Internet standards for group video conversations. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://andyet.com/team/nathan&quot;&gt;Fritzy&lt;/a&gt;, &lt;a href=&quot;https://andyet.com/team/hjon&quot;&gt;Hjon&lt;/a&gt;, and our friends at &lt;a href=&quot;http://www.steamclock.com/&quot;&gt;Steamclock&lt;/a&gt; have put a lot of effort into creating tools that will enable us to add these features over time to our native iOS app.&lt;/p&gt;
&lt;p&gt;And &lt;a href=&quot;https://andyet.com/team/bear&quot;&gt;Bear&lt;/a&gt; and &lt;a href=&quot;https://andyet.com/team/marcus&quot;&gt;Marcus Stong&lt;/a&gt; have created an operational foundation for rapidly building and scaling communication and collaboration applications, which we can run for you or help you run on your own hardware. (If you&apos;re interested, &lt;a href=&quot;mailto:contact@andyet.com&quot;&gt;we’d love to talk&lt;/a&gt;.)&lt;/p&gt;
&lt;h2 id=&quot;talky-and-otalk&quot;&gt;&lt;a href=&quot;#talky-and-otalk&quot; aria-label=&quot;talky and otalk permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Talky and Otalk&lt;/h2&gt;
&lt;p&gt;With Talky, we aren’t just building a product.&lt;/p&gt;
&lt;p&gt;We’re massively investing energy into open-source technology that will empower modern communication and collaboration apps to be built with open technologies, including tools that will make it easier to build native WebRTC applications for iOS, Android, Windows, Mac, and Linux.&lt;/p&gt;
&lt;p&gt;Otalk &lt;a href=&quot;https://blog.andyet.com/2014/09/08/introducing-otalk&quot;&gt;provides the foundation&lt;/a&gt; for Talky. It’s a suite of completely open and standards-based tools for making modern communication a delightful user and developer experience—and it’s &lt;a href=&quot;https://github.com/otalk&quot;&gt;all open sourced&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Creating these technologies represents a mammoth undertaking. Otalk is nothing less than the culmination of everything our team  members have learned from building and scaling realtime systems since the 90s, combined with everything we’ve learned in the last five years about building realtime apps for web and mobile.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Talky 2 will be the first software we’ve released built entirely on top of Otalk.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-are-we-doing-this-otalk-thing&quot;&gt;&lt;a href=&quot;#why-are-we-doing-this-otalk-thing&quot; aria-label=&quot;why are we doing this otalk thing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why are we doing this Otalk thing?&lt;/h2&gt;
&lt;p&gt;As firm proponents of the Open Web, we naturally believe in the power of Open Communication.&lt;/p&gt;
&lt;p&gt;There are Really Big Things™ that the Open Web makes more possible than any previous human invention. Things like democracy, equality, freedom, and distribution of power.&lt;/p&gt;
&lt;p&gt;The Web is rapidly evolving. More and more of our experience on the web rely on extremely advanced technologies—the majority of which are closed silos.&lt;/p&gt;
&lt;p&gt;It’s nearly impossible to build a quality communication app without either a deep understanding of a huge swath of tech or by leveraging one of a small handful of private services—let alone doing it in an open and interoperable way. That&apos;s not good enough.&lt;/p&gt;
&lt;p&gt;Alan Kay famously said, “The best way to predict the future is to invent it.”&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet, we&apos;re more than a little concerned that the trend of the web is toward consolidation of power and oligarchy.&lt;/p&gt;
&lt;p&gt;We’re not opposed to business in general (we are one); we simply believe there’s a better future waiting to be invented and we&apos;re not afraid to try.&lt;/p&gt;
&lt;h2 id=&quot;join-us&quot;&gt;&lt;a href=&quot;#join-us&quot; aria-label=&quot;join us permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Join us&lt;/h2&gt;
&lt;p&gt;Want to be the first to know when Talky 2 is ready and stay up to date on Otalk? Want to give us input and feedback to help guide features? Join our community! We can&apos;t be &amp;#x26;yet without &amp;#x26;you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Breakdown of the Ampersand.js implementation on TodoMVC.com]]></title><description><![CDATA[TodoMVC is a neat project with a simple idea: to build the same application with a whole slew of different frameworks so we can compare how…]]></description><link>https://blog.andyet.com/2014/10/20/breakdown-of-ampersand-todomvc-implementation/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/20/breakdown-of-ampersand-todomvc-implementation/</guid><pubDate>Mon, 20 Oct 2014 13:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://todomvc.com&quot;&gt;TodoMVC&lt;/a&gt; is a neat project with a simple idea: to build the same application with a whole slew of different frameworks so we can compare how they solve the same problems.&lt;/p&gt;
&lt;p&gt;The project&apos;s maintainers &lt;a href=&quot;https://github.com/tastejs/todomvc#936&quot;&gt;asked me to contribute&lt;/a&gt; an example in &lt;a href=&quot;http://ampersandjs.com&quot;&gt;Ampersand.js&lt;/a&gt;, so that&apos;s what we did. &lt;/p&gt;
&lt;p&gt;There are a few aspects of the implementation that I thought were worth writing up.&lt;/p&gt;
&lt;h2 id=&quot;first-some-highlights&quot;&gt;&lt;a href=&quot;#first-some-highlights&quot; aria-label=&quot;first some highlights permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;First, some highlights&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;filesize:&lt;/strong&gt; Total filesize of &lt;em&gt;all the JS assets required for the app&lt;/em&gt; only &lt;strong&gt;24kb&lt;/strong&gt;(minified/gzipped) which, for comparison, is smaller than jQuery &lt;em&gt;by itself&lt;/em&gt;. By comparison the Ember.js version is &lt;strong&gt;165kb&lt;/strong&gt; and that&apos;s without including compiled templates.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;super efficient DOM updating:&lt;/strong&gt; Nothing is re-rendered to the DOM just because the underlying model changed. Only state changes that result in a different outcome touch the DOM at all, and when we &lt;em&gt;do&lt;/em&gt; need to update the DOM because of a state change, it&apos;s done using specific DOM methods such as &lt;code class=&quot;language-text&quot;&gt;.setAttribute&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;.innerText&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;.classList.add&lt;/code&gt;, etc. and generally not with &lt;code class=&quot;language-text&quot;&gt;.innerHTML&lt;/code&gt;. This matters because &lt;code class=&quot;language-text&quot;&gt;innerHTML&lt;/code&gt; is slower, because it requires the browser to parse HTML. The point is that after the initial render, it does the &lt;em&gt;absolute minimum&lt;/em&gt; number of DOM updates required, and does them as efficiently as possible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;good code hygiene:&lt;/strong&gt; Maintainable, readable code. All state stored in models, zero state stored in the DOM. Fully valid HTML (I&apos;m looking at you, Angular). Call me old school, but behavior is in JS, styles is in CSS, and structure is in HTML.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;fully template language agnostic:&lt;/strong&gt; We&apos;re using &lt;a href=&quot;http://jade-lang.com/&quot;&gt;jade&lt;/a&gt; here, but it really doesn&apos;t matter because the bindings are all handled outside of the templating, as we&apos;ll see later. You could easily use the template language of your choice, or even plain HTML strings. &lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ok, now let&apos;s get into some more of the details.&lt;/p&gt;
&lt;h2 id=&quot;persisting-todos-to-localstorage&quot;&gt;&lt;a href=&quot;#persisting-todos-to-localstorage&quot; aria-label=&quot;persisting todos to localstorage permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Persisting todos to localStorage&lt;/h2&gt;
&lt;p&gt;The TodoMVC project&apos;s &lt;a href=&quot;https://github.com/tastejs/todomvc/blob/master/app-spec.md&quot;&gt;app spec&lt;/a&gt; specifies:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Your app should dynamically persist the todos to localStorage. If the framework has capabilities for persisting data (i.e. Backbone.sync), use that, otherwise use vanilla localStorage. If possible, use the keys &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;title&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;completed&lt;/code&gt; for each item. Make sure to use this format for the localStorage name: &lt;code class=&quot;language-text&quot;&gt;todos-[framework]&lt;/code&gt;. Editing mode should not be persisted.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is ridiculously easy in Ampersand. This could be done this as a mixin, so we could use the &quot;backbone-esque&quot; &lt;code class=&quot;language-text&quot;&gt;.save()&lt;/code&gt; methods on the models. But given how straightforward this use case is, it&apos;s simpler to just do it directly. We simply create two methods.&lt;/p&gt;
&lt;p&gt;One to write the data to &lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;writeToLocalStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  localStorage&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;STORAGE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One to retrieve it: &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;readFromLocalStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; existingData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; localStorage&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;STORAGE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existingData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;existingData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&apos;ll notice we&apos;re just passing &lt;code class=&quot;language-text&quot;&gt;this&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;JSON.stringify&lt;/code&gt;. This works because ampersand collection has a &lt;code class=&quot;language-text&quot;&gt;toJSON()&lt;/code&gt; method and the spec for the browser&apos;s built-in &lt;code class=&quot;language-text&quot;&gt;JSON&lt;/code&gt; interface states that it will look for and call a &lt;code class=&quot;language-text&quot;&gt;toJSON&lt;/code&gt; method on the object passed in, if present. So rather than doing &lt;code class=&quot;language-text&quot;&gt;JSON.stringify(this.toJSON())&lt;/code&gt;, we can just do &lt;code class=&quot;language-text&quot;&gt;JSON.stringify(this)&lt;/code&gt;. Ampersand collection&apos;s &lt;code class=&quot;language-text&quot;&gt;toJSON&lt;/code&gt; is simply an alias to &lt;code class=&quot;language-text&quot;&gt;serialize&lt;/code&gt; which loops through the models it contains and calls each of their &lt;code class=&quot;language-text&quot;&gt;serialize&lt;/code&gt; methods and returns them all as a serializable array.&lt;/p&gt;
&lt;p&gt;So far we&apos;ve just created the methods and not actually used them, so how do we wire that up?&lt;/p&gt;
&lt;p&gt;Well, given how simple the app requirements are in this case: &quot;save everything when stuff changes,&quot; we can just have the collection watch itself and persist when it changes. Then our models don&apos;t even have to know or care how they get persisted, the collection will watch itself, and whenever we add/remove or change something it&apos;ll re-save itself. This keeps our logic nicely encapsulated into the collection whose responsibility it is to deal with models. Makes sense, right?&lt;/p&gt;
&lt;p&gt;Turns out, that&apos;s quite easy too. Inside our collection&apos;s initialize method, we&apos;ll do as follows. See line comments below:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Attempt to read from localStorage right away&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// this also adds them to the collection&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFromLocalStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// We put a slight debounce on this since it could possibly&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// be called in rapid succession. We&apos;re using a small npm package&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// called &apos;debounce&apos; for this: &lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// https://www.npmjs.org/package/debounce&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writeToLocalStorage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;debounce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writeToLocalStorage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// We listen for changes to the collection&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// and persist on change&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;all&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writeToLocalStorage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;syncing-between-multiple-open-tabs&quot;&gt;&lt;a href=&quot;#syncing-between-multiple-open-tabs&quot; aria-label=&quot;syncing between multiple open tabs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Syncing between multiple open tabs&lt;/h2&gt;
&lt;p&gt;Even though it&apos;s not specified in the spec, we went ahead and handled the case where you&apos;ve got the app open in multiple tabs in the same browser. In most of the other implementations, this case isn&apos;t covered, but it feels like it should be. Turns out, this is quite simple as well.&lt;/p&gt;
&lt;p&gt;We simply add the following line to our &lt;code class=&quot;language-text&quot;&gt;initialize&lt;/code&gt; method in our collection, which listens for &lt;code class=&quot;language-text&quot;&gt;storage&lt;/code&gt; events from the &lt;code class=&quot;language-text&quot;&gt;window&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;storage&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleStorageEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The corresponding handler inside our collection looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;handleStorageEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;key &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;STORAGE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readFromLocalStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The event argument passed to our &lt;code class=&quot;language-text&quot;&gt;storage&lt;/code&gt; event handler will includes a &lt;code class=&quot;language-text&quot;&gt;key&lt;/code&gt; property which we can use to determine which &lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt; value changed. These &lt;code class=&quot;language-text&quot;&gt;storage&lt;/code&gt; events don&apos;t fire in the tab that caused them, and they only fire in other tabs if the data is actually different. This seems perfect for our case. So we simply check to see if the change was to the key we&apos;re storing to, run &lt;code class=&quot;language-text&quot;&gt;readFromLocalStorage&lt;/code&gt;, and we&apos;re good.&lt;/p&gt;
&lt;p&gt;That&apos;s it! &lt;a href=&quot;https://github.com/tastejs/todomvc/blob/master/examples/ampersand/js/models/todos.js&quot;&gt;Here&apos;s the final collection code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;note:&lt;/strong&gt; It&apos;s worth noting that the app spec for TodoMVC is a bit contrived (understandably). If you&apos;re going to use &lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt; in a real app you should beware that it is shared by all open tabs of your app, as well as the fact that your data schema may change in a future version. To address these issues, consider namespacing your &lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt; keys with a version number to avoid conflicts. While all these problems can be solved, in most production cases you probably shouldn&apos;t treat &lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt; as anything other than an somewhat untrustworthy cache. If it uses it to store something important and the user clears their browser data, it&apos;s all gone. Also, you can&apos;t always trust that you&apos;ll get valid JSON back, so a try/catch would probably be wise as well.&lt;/p&gt;
&lt;h2 id=&quot;session-properties-for-code-classlanguage-texteditingcode-state&quot;&gt;&lt;a href=&quot;#session-properties-for-code-classlanguage-texteditingcode-state&quot; aria-label=&quot;session properties for code classlanguage texteditingcode state permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Session properties for &lt;code class=&quot;language-text&quot;&gt;editing&lt;/code&gt; state&lt;/h2&gt;
&lt;p&gt;If you paid close attention, you noticed the TodoMVC application spec also says we shouldn&apos;t persist the &lt;code class=&quot;language-text&quot;&gt;editing&lt;/code&gt; state of a todo. This refers to the fact that you can double-click a task to put it into edit mode. &lt;/p&gt;
&lt;p&gt;One thing that&apos;s a bit unique in Ampersand is its use of what we call &quot;session properties&quot; to store things like the &lt;code class=&quot;language-text&quot;&gt;editing&lt;/code&gt; state.&lt;/p&gt;
&lt;p&gt;If you look at the other examples, both Ember and Backbone only reference the &quot;editing&quot; state in the view code or the view controller; there&apos;s no reference to it in the models. Compare that to our todo model:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; State &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-state&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; State&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// These properties get persisted to localStorage&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// because they&apos;ll be included when serializing&lt;/span&gt;
  props&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    title&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    completed&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;boolean&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// session properties are *identical* to `props`&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// *except* that they&apos;re not included when serializing.&lt;/span&gt;
  session&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// here we declare that editing state, just like&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// the properties above.&lt;/span&gt;
    editing&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;boolean&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// This is just a convenience method that just&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// gives our view a simple method to call when &lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// it wants to trash a todo.&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;collection&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You might be thinking, WHAT!? You&apos;re storing &lt;em&gt;view state in the models?!&lt;/em&gt; &lt;/p&gt;
&lt;p&gt;Yes. Well... sort of.&lt;/p&gt;
&lt;p&gt;If you think about it, is it &lt;em&gt;really&lt;/em&gt; view state? I&apos;d argue it&apos;s &quot;application state,&quot; or really &quot;session state&quot; that&apos;s very clearly tied to that particular model instance. &lt;/p&gt;
&lt;p&gt;Conceptually, at least to me, it&apos;s clear that it&apos;s actually a state of the model. The view is not in &quot;editing&quot; mode; the model is. &lt;/p&gt;
&lt;p&gt;How the view or the rest of the app deals with that information is irrelevant. The fact is, when a user edits a todo, they have put &lt;em&gt;that particular todo&lt;/em&gt; into an editing &lt;em&gt;state&lt;/em&gt;. That has nothing to do with a particular view of that model.&lt;/p&gt;
&lt;p&gt;This distinction becomes even more apparent if your app needs to do &lt;em&gt;something else&lt;/em&gt; based on that state information, such as disabling application-wide keyboard shortcuts, or applying a class to the todo-list container element when it&apos;s in edit mode.&lt;/p&gt;
&lt;p&gt;Even if you disagree with that, what about readability? Let&apos;s say you&apos;re working with a team on this app, where can they go to see all the state we&apos;re storing related to a single todo?&lt;/p&gt;
&lt;p&gt;In the Backbone.js example the model code reads like this: &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Todo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Backbone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Default attributes for the todo&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// and ensure that each todo created has `title` and `completed` keys.&lt;/span&gt;
  defaults&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    title&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &apos;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    completed&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// Toggle the `completed` state of this todo item.&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;toggle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      completed&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;completed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and in Ember:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;Todos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Todo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  title&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  isCompleted&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;DS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;boolean&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Neither of these give any indication that we also care about whether a model is in &lt;code class=&quot;language-text&quot;&gt;editing&lt;/code&gt; mode or not. We&apos;d have to dig into the view to see that. In an app this simple, it&apos;s not a big deal. In a big app this kind of thing gets problematic very quickly.&lt;/p&gt;
&lt;p&gt;It feels so much clearer to see all the types of state related to that model in a single place. &lt;/p&gt;
&lt;h2 id=&quot;using-a-subcollection-to-get-filtered-views-of-the-todos&quot;&gt;&lt;a href=&quot;#using-a-subcollection-to-get-filtered-views-of-the-todos&quot; aria-label=&quot;using a subcollection to get filtered views of the todos permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using a subcollection to get filtered views of the todos&lt;/h2&gt;
&lt;p&gt;The spec says we should have 3 different view modes for our todos:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All todos&lt;/li&gt;
&lt;li&gt;Remaining todos&lt;/li&gt;
&lt;li&gt;Completed todos&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are a few different ways we could go about this. We&apos;ve got our trusty &lt;a href=&quot;https://github.com/AmpersandJS/ampersand-collection-view&quot;&gt;ampersand-collection-view&lt;/a&gt; which will take a collection and render a view for each item in the collection. It also takes care of adding and removing items if the collection changes, as well as cleaning up event handlers if the parent view is destroyed. &lt;/p&gt;
&lt;p&gt;That collection view is &lt;a href=&quot;http://ampersandjs.com/docs#ampersand-view-rendercollection&quot;&gt;included in ampersand-view&lt;/a&gt; and is exposed as a simple method: &lt;code class=&quot;language-text&quot;&gt;renderCollection&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One way to accomplish what&apos;s being asked in the spec would be to create three different collections and shuffle todos around between collections based on their &lt;code class=&quot;language-text&quot;&gt;completed&lt;/code&gt; state. But that feels a bit weird. Because we really only have &lt;em&gt;one item type&lt;/em&gt;. We could also have a single base collection and request a new filtered list of todos from that collection each time any of them changes, which is how the Backbone.js implementation does it. But that would mean that it&apos;s no longer just a rendered collection. Instead we&apos;d have to re-render a view for each todo in the matching set, which doesn&apos;t feel very clean or efficient.&lt;/p&gt;
&lt;p&gt;It seems cleaner/easier to just have a single todos collection and then render a &quot;filtered view,&quot; if you will. Ideally, we&apos;d just be able to set a &lt;code class=&quot;language-text&quot;&gt;mode&lt;/code&gt; of that filtered view and have it add/remove as necessary.&lt;/p&gt;
&lt;p&gt;So we want something that &lt;em&gt;behaves&lt;/em&gt; like a normal collection, but which is really just a &lt;em&gt;subset&lt;/em&gt; of that collection.&lt;/p&gt;
&lt;p&gt;Then we could still just call &lt;code class=&quot;language-text&quot;&gt;renderCollection&lt;/code&gt; once, using that subcollection.&lt;/p&gt;
&lt;p&gt;Then if we change the filtering rules of the subcollection things would Just Work™. In ampersand we&apos;ve got just such a thing in &lt;a href=&quot;https://github.com/AmpersandJS/ampersand-subcollection&quot;&gt;ampersand-subcollection&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;If you give it collection to use as a base and a set of rules like filters, a max length, or its own sorting order, then it pretends to be a &quot;real&quot; collection. It has a &lt;code class=&quot;language-text&quot;&gt;models&lt;/code&gt; array of its current models, a &lt;code class=&quot;language-text&quot;&gt;length&lt;/code&gt; property, its own comparator, and it will fire events like add/remove/change/sort as the underlying data in the base collection changes, but it will fire those events based on its own defined filters and rules.&lt;/p&gt;
&lt;p&gt;So, let&apos;s use that. In this case we just need a single subcollection, so we&apos;ll just create it and attach it to the collection as part of its &lt;code class=&quot;language-text&quot;&gt;initialize&lt;/code&gt; method:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Collection &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-collection&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; SubCollection &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-subcollection&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Todo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./todo&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Collection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  model&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Todo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// This is what we&apos;ll actually render&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// it&apos;s a subcollection of the whole todo collection&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// that we&apos;ll add/remove filters to accordingly.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SubCollection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, rather than just rendering our collection, in our main view we&apos;ll render the subcollection instead:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderCollection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;todos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TodoView&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;queryByHook&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;todo-container&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&apos;ll talk about model structure in just a minute, but for now let&apos;s just realize that &lt;code class=&quot;language-text&quot;&gt;app.model.todos&lt;/code&gt; is our todos collection and &lt;code class=&quot;language-text&quot;&gt;app.model.todos.subset&lt;/code&gt; was the subcollection we just created above.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;TodoView&lt;/code&gt; is the constructor (a.k.a. view class) for the view we want to use to render the items in the collection and &lt;code class=&quot;language-text&quot;&gt;this.queryByHook(&amp;#39;todo-container&amp;#39;)&lt;/code&gt; will return the DOM element we want to render these into. If you&apos;re curious about &lt;code class=&quot;language-text&quot;&gt;queryByHook&lt;/code&gt;, see &lt;a href=&quot;http://ampersandjs.com/learn/data-hook-attribute&quot;&gt;this explanation of why we use &lt;code class=&quot;language-text&quot;&gt;data-hook&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, now we can just re-configure that subcollection and it will fire add/remove events for changes based on those filters and our collection renderer will update accordingly.&lt;/p&gt;
&lt;p&gt;There are three valid states for the view mode we&apos;re in. It can be &lt;code class=&quot;language-text&quot;&gt;&amp;quot;active&amp;quot;&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;&amp;quot;completed&amp;quot;&lt;/code&gt;, or &lt;code class=&quot;language-text&quot;&gt;&amp;quot;all&amp;quot;&lt;/code&gt;. So now we create a simple helper method on the collection that configures it based on the &lt;code class=&quot;language-text&quot;&gt;mode&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function-variable function&quot;&gt;setMode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mode &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;all&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clearFilters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      where&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        completed&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mode &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;completed&apos;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So where does that mode come from? Let&apos;s look at our model structure.&lt;/p&gt;
&lt;h2 id=&quot;modeling-state&quot;&gt;&lt;a href=&quot;#modeling-state&quot; aria-label=&quot;modeling state permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Modeling state&lt;/h2&gt;
&lt;p&gt;In Ampersand a common pattern is to create a &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; model to represent state for the user of the app. If the user is logged in and has a username or other attributes, we&apos;d store them as &lt;code class=&quot;language-text&quot;&gt;props&lt;/code&gt; on the &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; model. In this app, there&apos;s no persisted &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; properties, but we do still have a user of the app we want to model and that user has a set of todos that belong to them. So we&apos;ll create that as a collection property on the &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; object like so:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; State &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-state&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Todos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./todos&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; State&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  collections&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    todos&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Todos
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Things that otherwise represent &quot;session state&quot; or other cached data related to the user can be attached to the &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; model as &lt;code class=&quot;language-text&quot;&gt;session&lt;/code&gt; properties as we described above.&lt;/p&gt;
&lt;p&gt;Something like the &lt;code class=&quot;language-text&quot;&gt;mode&lt;/code&gt; we described above fits into that category.&lt;/p&gt;
&lt;p&gt;Ideally, we should be able to simply change the &lt;code class=&quot;language-text&quot;&gt;mode&lt;/code&gt; on the &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; model and everything else should just happen.&lt;/p&gt;
&lt;p&gt;And, since we&apos;re using ampersand-state, we can change the entire mode of the app with a simple assignment, as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;all&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Go ahead and open a console on &lt;a href=&quot;http://todomvc.com/examples/ampersand&quot;&gt;the app page&lt;/a&gt; and try setting it to various things. Note that it will only &lt;em&gt;let&lt;/em&gt; you set it to a valid value. If you try doing: &lt;code class=&quot;language-text&quot;&gt;app.me.mode = &amp;#39;garbage&amp;#39;&lt;/code&gt; you&apos;ll get this error:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.cloudup.com/LRGNTCDg6L-2000x2000.png&quot; alt=&quot;type error&quot;&gt;&lt;/p&gt;
&lt;p&gt;This type of defensive programming is hugely helpful for catching errors in other parts of your app.&lt;/p&gt;
&lt;p&gt;This works because we&apos;ve defined &lt;code class=&quot;language-text&quot;&gt;mode&lt;/code&gt; as a session property on our &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; model like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;mode&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  values&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;all&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;completed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;active&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;all&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It&apos;s readable and behaves as you&apos;d expect.&lt;/p&gt;
&lt;h2 id=&quot;calculating-various-lengthstotals&quot;&gt;&lt;a href=&quot;#calculating-various-lengthstotals&quot; aria-label=&quot;calculating various lengthstotals permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Calculating various lengths/totals&lt;/h2&gt;
&lt;p&gt;The app spec states we must show counts of &quot;items left&quot; and &quot;items completed,&quot; plus we have to be able to know if there aren&apos;t any items at all in the collection so we can hide the header and footer.&lt;/p&gt;
&lt;p&gt;This means we need to track 3 different calculated totals at all times. &lt;/p&gt;
&lt;p&gt;Ultimately if this is state we care about, we want them to be easily readable as part of a model definition. Since we have a &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; model that contains the &lt;code class=&quot;language-text&quot;&gt;mode&lt;/code&gt; and has a child collection of &lt;code class=&quot;language-text&quot;&gt;todos&lt;/code&gt;, it makes sense for it to care about and track those totals. So we&apos;ll create &lt;code class=&quot;language-text&quot;&gt;session&lt;/code&gt; properties for all of those totals too.&lt;/p&gt;
&lt;p&gt;In the &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; model&apos;s &lt;code class=&quot;language-text&quot;&gt;initialize&lt;/code&gt; we can listen to events in our collection that we know will affect these totals, and then we have a single method &lt;code class=&quot;language-text&quot;&gt;handleTodosUpdate&lt;/code&gt; that calculates and sets those totals.&lt;/p&gt;
&lt;p&gt;The totals are quite easy; we check &lt;code class=&quot;language-text&quot;&gt;todos.length&lt;/code&gt; for &lt;code class=&quot;language-text&quot;&gt;totalCount&lt;/code&gt;, loop through once to calculate how many items are completed for &lt;code class=&quot;language-text&quot;&gt;completedCount&lt;/code&gt;, then use simple arithmetic for &lt;code class=&quot;language-text&quot;&gt;activeCount&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;Just for clarity, we also then set a boolean value for whether all of them are completed or not. This is because the spec states that if you go through and check all the items in the list, that the &quot;check all&quot; checkbox at the top should also check itself. Tracking that state as a separate boolean makes it nice and clear.&lt;/p&gt;
&lt;p&gt;So, now our &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; models looks something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token function-variable function&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Listen to changes to the todos collection that will&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// affect lengths we want to calculate.&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listenTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;todos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;change:completed change:title add remove&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleTodosUpdate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;token comment&quot;&gt;// We also want to calculate these values once on init&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleTodosUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Define our session properties&lt;/span&gt;
session&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  activeCount&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  completedCount&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  totalCount&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;number&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  allCompleted&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;boolean&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  mode&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    values&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;all&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;completed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;active&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;all&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Calculate and set various lengths we&apos;re&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// tracking. We set them as session properties&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// so they&apos;re easy to listen to and bind to DOM&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// where needed.&lt;/span&gt;
&lt;span class=&quot;token function-variable function&quot;&gt;handleTodosUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; completed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; todos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;todos&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  todos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;todo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;todo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;completed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      completed&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Here we set all our session properties&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    completedCount&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; completed&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    activeCount&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; completed&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    totalCount&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    allCompleted&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; todos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; completed
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At this point we have all the state we want to track for the entire app. None of it is mixed into any of the view logic. We&apos;ve got an entire completely de-coupled data layer that tracks all state for the app.&lt;/p&gt;
&lt;p&gt;You can see the &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; model in its entirety as currently deployed &lt;a href=&quot;https://github.com/tastejs/todomvc/blob/master/examples/ampersand/js/models/me.js&quot;&gt;on github&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;routing&quot;&gt;&lt;a href=&quot;#routing&quot; aria-label=&quot;routing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Routing&lt;/h2&gt;
&lt;p&gt;Once we&apos;ve done all of this state management, the router becomes super simple. &lt;/p&gt;
&lt;p&gt;We&apos;ve already created a &lt;code class=&quot;language-text&quot;&gt;mode&lt;/code&gt; flag on the &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; that actually controls everything. &lt;/p&gt;
&lt;p&gt;So all we have to do is set the proper &lt;code class=&quot;language-text&quot;&gt;mode&lt;/code&gt; based on the URL, which we can do like so:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Router &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ampersand-router&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  routes&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// this matches all urls&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&apos;*filter&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;setFilter&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;setFilter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// if we passed one, set it&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// if not set it to &quot;all&quot;&lt;/span&gt;
    app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; arg &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;all&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;views&quot;&gt;&lt;a href=&quot;#views&quot; aria-label=&quot;views permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Views&lt;/h2&gt;
&lt;p&gt;At this point it&apos;s really all a matter of wiring things up to the views. The views contain very little actual logic. They simply declare how things should be rendered, what data should be bound where, and turn user actions into changes in our state layer.&lt;/p&gt;
&lt;p&gt;For this app, the &lt;code class=&quot;language-text&quot;&gt;index.html&lt;/code&gt; file contains the layout HTML already. So the &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; view is just going to attach itself to the &lt;code class=&quot;language-text&quot;&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag as you can see in our &lt;code class=&quot;language-text&quot;&gt;app.js&lt;/code&gt; file, below. We simply hand it the existing &lt;code class=&quot;language-text&quot;&gt;document.body&lt;/code&gt; and never call &lt;code class=&quot;language-text&quot;&gt;render()&lt;/code&gt; because it&apos;s already there.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; MainView &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./views/main&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Me &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./models/me&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Router &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;./router&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function-variable function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Model representing state for&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// user using the app. Calling it&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// &apos;me&apos; is a bit of convention but&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// it&apos;s basically &apos;app state&apos;.&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;me &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Me&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// Our main view&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MainView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      el&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      model&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;me
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Create and fire up the router&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;router &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;history&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The views in this particular app handle all bindings declaratively as described by the &lt;code class=&quot;language-text&quot;&gt;bindings&lt;/code&gt; property of the views. It might feel a tad verbose, but it&apos;s also very precise. This way you, as the developer, can decide whether you want to just render things into the template on first render, or whether you want to bind things. It&apos;s also useful for publishing re-usable views. Because you don&apos;t have to include any templating library as part of your re-usable views. &lt;/p&gt;
&lt;p&gt;Templates and views are easily the most debate-inducing portion of modern JS apps, but the main point is that Ampersand.js gives you an agnostic way of doing data binding that&apos;s there if you want it, but completely gets out of your way if you&apos;d rather use something like &lt;a href=&quot;http://handlebarsjs.com&quot;&gt;Handlebars&lt;/a&gt; or &lt;a href=&quot;http://facebook.github.io/react&quot;&gt;React&lt;/a&gt; to handle your view layer. &lt;/p&gt;
&lt;p&gt;That&apos;s the whole point of the modular architecture of Ampersand.js: &lt;em&gt;optimize for flexibility, install only what you want to use&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For a full reference of all the data binding types you can use, &lt;a href=&quot;http://ampersandjs.com/docs#ampersand-dom-bindings-binding-types&quot;&gt;see the reference documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Below are the declarative bindings from the main view with comments describing what each does. &lt;/p&gt;
&lt;p&gt;Note that &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; in this case is the &lt;code class=&quot;language-text&quot;&gt;me&lt;/code&gt; model. So &lt;code class=&quot;language-text&quot;&gt;model.totalCount&lt;/code&gt;, for example, is referencing the &lt;code class=&quot;language-text&quot;&gt;me.totalCount&lt;/code&gt; session property discussed above. If you really prefer tracking state in your view code, it&apos;s easy to do so. Simply add a &lt;code class=&quot;language-text&quot;&gt;props&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;session&lt;/code&gt; properties just like you would in a model, and everything still works.&lt;/p&gt;
&lt;p&gt;It&apos;s worth noting that with the way we&apos;ve declared bindings in the app they still work if you replaced &lt;code class=&quot;language-text&quot;&gt;this.el&lt;/code&gt;, or if &lt;code class=&quot;language-text&quot;&gt;this.model&lt;/code&gt; was changed or didn&apos;t exist at the time of first render. They would still be set and updated accordingly.&lt;/p&gt;
&lt;p&gt;Many times in real apps, these binding declarations are simpler than this example, but on the plus side it serves as a good demo of the types of bindings that are available. Here&apos;s the data binding section from our &lt;code class=&quot;language-text&quot;&gt;js/views/main.js&lt;/code&gt; view:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;

bindings&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Toggles visibility of main and footer&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// based on truthiness of totalCount.&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Since zero is falsy it won&apos;t show if&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// total is zero.&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;model.totalCount&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// this is the binding type&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;toggle&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// this is just a CSS selector&lt;/span&gt;
    selector&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;#main, #footer&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// This is how you do multiple bindings&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// to a single property. Just pass an &lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// array of bindings.&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;model.completedCount&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Hides the clear-completed span&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// when there are no completed items&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;toggle&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// &quot;hook&quot; here is shortcut for &lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// selector: &apos;[data-hook=clear-completed]&apos;&lt;/span&gt;
      hook&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;clear-completed&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// Inserts completed count as text&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// into the span&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;text&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      hook&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;completed-count&apos;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// This is an HTML string that we made&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// as a derived (a.k.a. computed) property&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// of the `me` model. This was done this way&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// for simplicity because the target HTML&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// looks like this: &lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// &quot;&amp;lt;strong&gt;5&amp;lt;/strong&gt; items left&quot;&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// where &quot;items&quot; has to be correctly pluralized&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// since it&apos;s not just text, but not really&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// a bunch of nested HTML it was easier to just&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// bind this as `innerHTML`.&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;model.itemsLeftHtml&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;innerHTML&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    hook&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;todo-count&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// This adds the &apos;selected&apos; class to the right&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// element in the footer&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;model.mode&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;switchClass&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;selected&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    cases&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;all&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[data-hook=all-mode]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;active&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[data-hook=active-mode]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&apos;completed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;[data-hook=completed-mode]&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Bind &apos;checked&apos; state of `mark-all`&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// checkbox at the top&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&apos;model.allCompleted&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;booleanAttribute&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    name&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;checked&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    hook&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;mark-all&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;a-few-closing-thoughts&quot;&gt;&lt;a href=&quot;#a-few-closing-thoughts&quot; aria-label=&quot;a few closing thoughts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A few closing thoughts&lt;/h2&gt;
&lt;p&gt;I&apos;m excited that we were asked to contribute an example to TodoMVC. Big thanks to &lt;a href=&quot;https://twitter.com/lukekarrys&quot;&gt;Luke Karrys&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/philip_roberts&quot;&gt;Philip Roberts&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/wraithgar&quot;&gt;Gar&lt;/a&gt; for their help/feedback on building the app and to &lt;a href=&quot;https://twitter.com/sindresorhus&quot;&gt;Sindre Sordhus&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/addyosmani&quot;&gt;Addy Osmani&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/passy&quot;&gt;Pascal Hartig&lt;/a&gt; for their hard work on the TodoMVC project, as it&apos;s quite useful for comparing available tools.&lt;/p&gt;
&lt;p&gt;If you have any feedback ping me, &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; on twitter or &lt;a href=&quot;http://ampersandjs.com/contribute&quot;&gt;any of the other core contributors&lt;/a&gt; for that matter. You can also jump into the #&amp;#x26;yet IRC channel on freenode and tell us what you think. We&apos;re always working to improve.&lt;/p&gt;
&lt;p&gt;We think we&apos;ve created something that strikes a good balance between flexibility, expressiveness, readability, and power, and we&apos;re thrilled about the fast adoption and massive community contribution we&apos;ve seen in just a few short months since releasing Ampersand.js.&lt;/p&gt;
&lt;p&gt;I&apos;ll be speaking about frameworks in Brighton at &lt;a href=&quot;http://2014.full-frontal.org/&quot;&gt;FullFrontal&lt;/a&gt; in a few weeks, and then about Ampersand.js at &lt;a href=&quot;http://backboneconf.com/&quot;&gt;BackboneConf&lt;/a&gt; in December. Hope to see you then.&lt;/p&gt;
&lt;p&gt;If you like the philosophy and approaches described here, you might also enjoy my book, &lt;a href=&quot;http://humanjavascript.com&quot;&gt;Human JavaScript&lt;/a&gt;. If you want Ampersand.js training for your team &lt;a href=&quot;mailto:training@andyet.com?subject=Ampersand.js%20training&quot;&gt;get in touch with our training coordinator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See you on the Interwebz! &amp;#x3C;3&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How does the JavaScript event loop work?]]></title><description><![CDATA[Two of our core values on the &yet team are curiosity and generosity. That's why you'll so often find my yeti colleagues at the forefront of…]]></description><link>https://blog.andyet.com/2014/10/16/event-loop/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/16/event-loop/</guid><pubDate>Thu, 16 Oct 2014 10:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Two of our core values on the &lt;a href=&quot;https://andyet.com/&quot;&gt;&amp;#x26;yet&lt;/a&gt; team are curiosity and generosity. That&apos;s why you&apos;ll so often find my yeti colleagues at the forefront of various open-source projects, and also sharing their knowledge at technology and design conferences around the world. &lt;/p&gt;
&lt;p&gt;An outstanding example is the work that &lt;a href=&quot;https://andyet.com/team/phil&quot;&gt;Philip Roberts&lt;/a&gt; has done to understand how JavaScript really works within the browser, and to explain what he has discovered in a talk entitled &quot;What the Heck is the Event Loop, Anyway?&quot; (delivered at both &lt;a href=&quot;http://scotlandjs.com/&quot;&gt;ScotlandJS&lt;/a&gt; and &lt;a href=&quot;http://2014.jsconf.eu/&quot;&gt;JSConf EU&lt;/a&gt; in recent months). &lt;/p&gt;
&lt;p&gt;If you&apos;d like to know more about the inner workings of JavaScript, I highly recommend that you spend 30 minutes watching this video - it is fascinating and educational and entertaining all at the same time. (Because another yeti value is humility, you won&apos;t find Philip boasting about this talk, but I have no such reservations because it is seriously great stuff.)&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/8aGhZQkoFbQ&quot; frameborder=&quot;0&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8aGhZQkoFbQ&quot;&gt;What the Heck is the Event Loop, Anyway?&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[We can't be &yet without &you]]></title><description><![CDATA[&yet has long been a wandering band of souls—like a mix of the A-Team and the Island of Misfit Toys from Rudolph the Red-Nosed Reindeer.Over…]]></description><link>https://blog.andyet.com/2014/10/13/we-cant-be-andyet-without-andyou/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/13/we-cant-be-andyet-without-andyou/</guid><pubDate>Mon, 13 Oct 2014 15:36:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;#x26;yet has long been a wandering band of souls—like a mix of the &lt;em&gt;A-Team&lt;/em&gt; and the Island of Misfit Toys from &lt;em&gt;Rudolph the Red-Nosed Reindeer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Over five years, one thing that&apos;s been a constant for &amp;#x26;yet is &lt;em&gt;realtime&lt;/em&gt;. We&apos;ve worked our way through many technologies—some ancient, some nascent, and many of our own. We&apos;ve stayed focused on the users of those technologies—end users and developers.&lt;/p&gt;
&lt;p&gt;Our path forward has become clearer and more focused than it&apos;s ever been. Some of the terrific people we&apos;ve added to our team this last year have had tremendous influence on honing our focus. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We know the type of &lt;em&gt;company&lt;/em&gt; we aspire to be:&lt;/strong&gt; people first, and always determined to make things better for humans on all sides of our work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We know the type of &lt;em&gt;experiences&lt;/em&gt; we aim to create:&lt;/strong&gt; friendly, user-focused, and simple.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We know the types of &lt;em&gt;problems&lt;/em&gt; we want to solve:&lt;/strong&gt; we want to empower realtime software and the teams who build it, and we want to create a huge wake of open source that helps make communication technologies as open and accessible as the web itself.&lt;/p&gt;
&lt;p&gt;We have a clearer sense of focus than we&apos;ve ever had. But for us, there&apos;s one missing component.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In order for us to get where we want to go, we need you. The communities we are part of have shaped &amp;#x26;yet in instrumental ways.&lt;/p&gt;
&lt;p&gt;Blog posts are great, but they&apos;re not enough. We don&apos;t believe in blog post comments—we believe in conversations. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We want to invite our community to be a more intimate part of what we&apos;re doing here, and we want to use email as a way to share the things we&apos;re working on and learning and wondering about.&lt;/strong&gt;&lt;/p&gt;
&lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/static/0852f54d7a2f7f1b4973ee01ba7cb6c4/0a47e/%26you-logo-01.png&quot; style=&quot;display: block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 600px;&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom: 58.27814569536424%; position: relative; bottom: 0; left: 0; background-image: url(&amp;apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsSAAALEgHS3X78AAABP0lEQVQoz6VSv0vDUBDO3+Qf4iQ4OTjoVBCcdHV3F5RCoIhgkVpRKdWKSKHBgiBKkFBrmzSWBFvTJCbv1z3fa9MawSHYG46Pu/vujvtO4XOY8gMZcADp/0EGxOibJ/iySaqbwHTac5ZKkamMRPlnb/kyLuhJVdbJhAkX7mjDhUNU7Rx9cn1InBhOTFTrk1ML3/RJsYs8DOprLLxcMyGDBOwj8jduB4tnvKAflHuqRdyIrTaC8x4eYVi683PNUJRtPXy1A5YijzfEdXu0UkHXXVfZ9Y6NTYM0HZxvxXtGLPJrWriuBU7Ecvdh26eSDL8PFu0/+dt1UmrxWke1acMlIih2vrCxGbLKOy6ZqGzhbpienFJKWNFlVwP24tFZRQaphAbibACPLq7aGE+FmWgzAWwsC/z9JHN9GE8kp5l/7Bt9Ia0RfPtXpQAAAABJRU5ErkJggg==&amp;apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
    &lt;img class=&quot;gatsby-resp-image-image&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot; alt=&quot; you logo 01&quot; title src=&quot;/static/0852f54d7a2f7f1b4973ee01ba7cb6c4/0a47e/%26you-logo-01.png&quot; srcset=&quot;/static/0852f54d7a2f7f1b4973ee01ba7cb6c4/29fe9/%26you-logo-01.png 151w,
/static/0852f54d7a2f7f1b4973ee01ba7cb6c4/6728c/%26you-logo-01.png 303w,
/static/0852f54d7a2f7f1b4973ee01ba7cb6c4/0a47e/%26you-logo-01.png 600w&quot; sizes=&quot;(max-width: 600px) 100vw, 600px&quot;&gt;
  &lt;/span&gt;
  &lt;/a&gt;
&lt;p&gt;To that end, we are launching &amp;#x26;you, a mailing list with bi-weekly dispatches covering &lt;em&gt;all&lt;/em&gt; the things &amp;#x26;yet does and has learned, and we want you to be part of it. Your aspirations, your questions, your problems, your frustrations, your wishes, your hopes. What do you need? How can we help?&lt;/p&gt;
&lt;p&gt;We&apos;ll get into more of that as we go, but first, we need your name and email address to get the ball rolling. &lt;/p&gt;
&lt;p&gt;Join us. We need you!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Feature detection and implicit subscriptions]]></title><description><![CDATA[A web application is not the same as the service it uses, even if you wrote them both. If your service has an API, you should not make…]]></description><link>https://blog.andyet.com/2014/10/09/feature-detection/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/09/feature-detection/</guid><pubDate>Thu, 09 Oct 2014 10:30:00 GMT</pubDate><content:encoded>&lt;p&gt;A web application is not the same as the service it uses, even if you wrote them both. If your service has an API, you should not make assumptions about how the client application is going to use the API or the data.&lt;/p&gt;
&lt;p&gt;A successful API will likely have more than one client written for it, and the authors of those clients will have very different ideas about how to use the data. Maybe you&apos;ll consume the API internally for other uses as well. You can&apos;t predict the future, so part of separating your API concerns from your clients should be feature detection.&lt;/p&gt;
&lt;p&gt;For a real time application, feature detection is a great way to manage client subscriptions to data.&lt;/p&gt;
&lt;p&gt;As I discussed a few weeks ago, for realtime apps it&apos;s better to &lt;a href=&quot;https://blog.andyet.com/2014/09/23/send-hints-not-data&quot;&gt;send hints, not data&lt;/a&gt;. When a client deliberately subscribes to a data channel for updates on changes, that is an explicit subscription. By contrast, an implicit subscription occurs when a client advertises the features and data types it is capable of dealing with, and the server automatically subscribes it to the relevant data channels.&lt;/p&gt;
&lt;p&gt;Implicit subscriptions give the client more flexibility in getting data and give the service more flexibility in managing the channels over which it pushes data. Implicit subscriptions can also be affected by relationships with and the availability of other users.&lt;/p&gt;
&lt;p&gt;For example, in a collaboration application, I may be in a group. My client might support displaying the geographical location of users, so my client publishes a feature URI (say, &lt;a href=&quot;http://jabber.org/protocol/geoloc&quot;&gt;http://jabber.org/protocol/geoloc&lt;/a&gt;) to the service.
Since my client is a member of a group, the service might subscribe me to the geolocation of other users in the group, such as /adam/geolocation and /bill/geolocation. &lt;/p&gt;
&lt;p&gt;Using implicit subscriptions here saves the client from the hassle of managing all of these subscriptions when various events occur (when I first log in, when other users log in and out, when users are added and removed from the group, etc.). &lt;/p&gt;
&lt;p&gt;This keeps the concerns of the service separate from the concerns of the client. The service knows and cares which data feeds it is sending to the client, but the client doesn&apos;t care. The client only cares that the service sends the data types it supports and wants. The client doesn&apos;t need to know how these data feeds are organized at all, and so it shouldn&apos;t be up to the client to manage its subscriptions to them.&lt;/p&gt;
&lt;p&gt;In addition to subscriptions, feature publishing can affect the results I get back when I make an API call. When a client explicitly retrieve data about /users/bill, the service could send items related to Bill that my client has declared support/interest in. In the spirit of hypermedia APIs, the service could also suggest URIs of related information with the results of a query.&lt;/p&gt;
&lt;p&gt;Managing subscriptions for realtime web applications can be tedious. Using implicit subscriptions - by creatively combining feature detection, API calls, user presence and relationships, and recent queries - can give web apps and their authors a lot of flexibility without the tedium.&lt;/p&gt;
&lt;p&gt;--
Would you like our help with your architecture? Please &lt;a href=&quot;https://andyet.com/consulting/architecture&quot;&gt;contact us&lt;/a&gt;, we&apos;d be glad to help!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Tao of Ops: Managing installed server packages]]></title><description><![CDATA[Every Operations Team needs to maintain the system packages installed on their servers. There are various paths toward that goal, with one…]]></description><link>https://blog.andyet.com/2014/10/07/installed-packages/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/07/installed-packages/</guid><pubDate>Tue, 07 Oct 2014 11:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Every Operations Team needs to maintain the system packages installed on their servers. There are various paths toward that goal, with one extreme being to track the packages manually - a tedious, soul-crushing endeavor &lt;em&gt;even&lt;/em&gt; if you automate it using &lt;a href=&quot;http://puppetlabs.com/&quot;&gt;Puppet&lt;/a&gt;, &lt;a href=&quot;http://www.fabfile.org/&quot;&gt;Fabric&lt;/a&gt;, &lt;a href=&quot;https://www.getchef.com/&quot;&gt;Chef&lt;/a&gt;, or (our favorite at &lt;a href=&quot;https://andyet.com/&quot;&gt;&amp;#x26;yet&lt;/a&gt;) &lt;a href=&quot;http://www.ansible.com/&quot;&gt;Ansible&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Why? Because even when you automate, you have to be aware of what packages need to be updated. Automating &quot;apt-get upgrade&quot; will work, yes - but you won&apos;t discover any regression issues (and related surprises) until the next time you cycle an app or service.&lt;/p&gt;
&lt;p&gt;A more balanced approach is to automate the tedious aspects and let the Operations Team handle the parts that require a purposeful decision. How the upgrade step is performed, via automation or manually, is beyond the scope of this brief post. Instead, I&apos;ll focus on the first step: how to gather data that can be used to make the required decisions.&lt;/p&gt;
&lt;h2 id=&quot;gathering-data&quot;&gt;&lt;a href=&quot;#gathering-data&quot; aria-label=&quot;gathering data permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Gathering Data&lt;/h2&gt;
&lt;p&gt;The first step is to find out what packages need to be updated. To do that we will use the operating system&apos;s package manager. For the purposes of this post I&apos;ll use the apt utility for Debian/Ubuntu and yum for RedHat/Centos.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;apt-get -s dist-upgrade
yum list updates&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Apt will return output that looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
  libxfixes-dev
The following packages will be upgraded:
  base-files openssl tzdata
3 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Inst base-files [6.5ubuntu6.7] (6.5ubuntu6.8 Ubuntu:12.04/precise-updates [amd64])
Conf base-files (6.5ubuntu6.8 Ubuntu:12.04/precise-updates [amd64])
Inst tzdata [2014c-0ubuntu0.12.04] (2014e-0ubuntu0.12.04 Ubunt
Inst openssl [1.0.1-4ubuntu5.14] (1.0.1-4ubuntu5.17 Ubuntu:12.04/precise-security [amd64])&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yum will return output that contains:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Updated Packages
audit.x86_64       2.2-4.el6_5       rhel-x86_64-server-6
audit-libs.x86_64  2.2-4.el6_5       rhel-x86_64-server-6
avahi-libs.x86_64  0.6.25-12.el6_5.1 rhel-x86_64-server-6&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Both of these tools provide the core data we need: package name and version. Apt even gives us a clue that it&apos;s a security update - the presence of &quot;-security&quot; in the repo name. I imagine that yum can also provide that, I just haven&apos;t found the proper command line argument to use.&lt;/p&gt;
&lt;h2 id=&quot;the-next-step&quot;&gt;&lt;a href=&quot;#the-next-step&quot; aria-label=&quot;the next step permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Next Step&lt;/h2&gt;
&lt;p&gt;Having this data is still not enough – we need to gather, store, and then process it. - To that end I&apos;ll share a small Python program to parse the output from apt so the data can be stored. At &amp;#x26;yet we use &lt;a href=&quot;https://github.com/coreos/etcd&quot;&gt;etcd&lt;/a&gt; for storage, but any backend data store will suffice. Processing the data for each server reflects the second step of our path - reducing the firehose of data into actionable parts that can then be carried along the path for the next step.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;#!/usr/bin/env python
import json
import datetime
import subprocess
import etcd

hostname = subprocess.check_output([&amp;#39;uname&amp;#39;, &amp;#39;-h&amp;#39;])
ec       = etcd.Client(host=&amp;#39;127.0.0.1&amp;#39;, port=4001)
normal   = {}
security = {}
output   = subprocess.check_output([&amp;#39;apt-get&amp;#39;, &amp;#39;-s&amp;#39;, &amp;#39;dist-upgrade&amp;#39;])
for line in output.split(&amp;#39;\n&amp;#39;):
    if line.startswith(&amp;#39;Inst&amp;#39;):
        items      = line.split()
        pkgName    = items[1]
        oldVersion = items[2][1:-1]
        newVersion = items[3][1:]
        if &amp;#39;-security&amp;#39; in line:
            security[pkgName] = { &amp;#39;old&amp;#39;: oldVersion, &amp;#39;new&amp;#39;: newVersion }
        else:
            normal[pkgName] = { &amp;#39;old&amp;#39;: oldVersion, &amp;#39;new&amp;#39;: newVersion }
data = { &amp;#39;timestamp&amp;#39;: datetime.datetime.now().strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)),
         &amp;#39;normal&amp;#39;: normal,
         &amp;#39;security&amp;#39;: security,
       }
key = &amp;#39;/packages/%s&amp;#39; % hostname
ec.write(key, json.dumps(data))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you run this, you will get an entry in etcd for each server, with a list of packages that need updating.&lt;/p&gt;
&lt;p&gt;The remaining steps along the path are now attainable because the groundwork is done - for example, you can write other cron jobs to scan that list, check the timestamp, and produce a report for all servers that need updates. Heck, you can even use your trusty Ops Bot to generate an alert in your team chat channel if a server has gone more than a day without being checked or having a security update applied.&lt;/p&gt;
&lt;p&gt;The point is this - if you&apos;re not monitoring, you are guessing. The tool above enables you to monitor your installed package environment and that&apos;s the first step along the many varied paths toward mastering your server environments.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Choosing the right database for the job]]></title><description><![CDATA[The NoSQL "movement" in database design has been motivated by many factors (such as simplicity and scalability) and has resulted in many…]]></description><link>https://blog.andyet.com/2014/10/01/right-database/</link><guid isPermaLink="false">https://blog.andyet.com/2014/10/01/right-database/</guid><pubDate>Wed, 01 Oct 2014 10:30:00 GMT</pubDate><content:encoded>&lt;p&gt;The NoSQL &quot;movement&quot; in database design has been motivated by many factors (such as simplicity and scalability) and has resulted in many more choices among storage and retrieval solutions. Instead of a one-size-fits-all approach, you can choose a database that is optimized for your specific needs.&lt;/p&gt;
&lt;p&gt;So what are your needs, and how do you choose the right database for the job?&lt;/p&gt;
&lt;p&gt;If you don&apos;t need a database cluster, and can live with a single node and snapshot backups, then you can pretty much do whatever you want.&lt;/p&gt;
&lt;h2 id=&quot;the-cap-theorem&quot;&gt;&lt;a href=&quot;#the-cap-theorem&quot; aria-label=&quot;the cap theorem permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The CAP Theorem&lt;/h2&gt;
&lt;p&gt;If we assume you need a cluster for high availability, let&apos;s talk about the &lt;a href=&quot;https://en.wikipedia.org/wiki/CAP_theorem&quot;&gt;CAP Theorem&lt;/a&gt;. Wait, I just lost some of you to eye rolls and &quot;this doesn&apos;t apply to me,&quot; but please, hear me out.&lt;/p&gt;
&lt;p&gt;The CAP Theorem states that a distributed database can only have two of the following qualities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;consistency&lt;/strong&gt; (writes are in order, and you&apos;ll get the same answer from multiple servers at any point in that order)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;availability&lt;/strong&gt; (if a database node is running, you can always write to it)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;partition-tolerance&lt;/strong&gt; (even if database nodes can&apos;t communicate with each other, you can still read the data)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&apos;ve heard &quot;fast, good, cheap: pick two&quot; — right? Essentially, for any given data type, you get to pick two.&lt;/p&gt;
&lt;p&gt;In practice, there are only two realistic choices for any given database: consistence and partition-tolerance (&quot;CP&quot;) or availability and partition-tolerance (&quot;AP&quot;). &quot;CA&quot; doesn&apos;t really exist, because without partition tolerance, you don&apos;t have availability. &lt;a href=&quot;https://twitter.com/kellabyte/status/513873559739826176&quot;&gt;At least Kelly Sommers and Aphyr agree&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some databases assert that the CAP theorem doesn&apos;t apply to them. To see what happens when databases make claims that violate the CAP theorem, have a look at &lt;a href=&quot;https://twitter.com/aphyr&quot;&gt;Aphyr&lt;/a&gt;&apos;s &lt;a href=&quot;http://aphyr.com/tags/Jepsen&quot;&gt;Call Me Maybe&lt;/a&gt; series. Not all of these databases are bad though, sometimes they&apos;re simply claiming a tuned CP like &lt;a href=&quot;https://foundationdb.com/key-value-store/white-papers/the-cap-theorem/&quot;&gt;FoundationDB&lt;/a&gt; or a way of resolving consistency for you (which you still need to be cautious and aware of).&lt;/p&gt;
&lt;h2 id=&quot;what-you-get-with-cp-databases&quot;&gt;&lt;a href=&quot;#what-you-get-with-cp-databases&quot; aria-label=&quot;what you get with cp databases permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What You Get With CP Databases&lt;/h2&gt;
&lt;p&gt;Most SQL databases claim CP. This means that they guarantee consistency. You can still read during bad partitions, and you&apos;ll probably write to single place for any given table. But they&apos;re not available. If the master is down, and another hasn&apos;t been elected, you can&apos;t make writes.&lt;/p&gt;
&lt;p&gt;Most SQL databases scale very high for reads, because that load can easily be distributed, but they don&apos;t scale horizontally for writes while keeping consistency; a master-master SQL cluster must resolve write conflicts with timing or app intervention.
SQL servers can become unavailable for writes during high load of the master servers and outages that only effect master nodes. If your data is primarily about reading (a product database, a user database, etc.), then SQL is an excellent choice, and will scale very well for you.&lt;/p&gt;
&lt;p&gt;But let&apos;s say your use case is collaboration. With an SQL database, you&apos;ll soon have to start sharding your users and interactions to separate clusters to keep up with writes.
For collaboration use cases, your users are writing just as much as reading.&lt;/p&gt;
&lt;h2 id=&quot;considering-ap-databases&quot;&gt;&lt;a href=&quot;#considering-ap-databases&quot; aria-label=&quot;considering ap databases permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Considering AP Databases&lt;/h2&gt;
&lt;p&gt;It may be time to look at an AP database.&lt;/p&gt;
&lt;p&gt;Some of the best AP database clusters are based on the &lt;a href=&quot;http://en.wikipedia.org/wiki/Dynamo_%28storage_system%29&quot;&gt;Dynamo&lt;/a&gt; whitepaper by Amazon.&lt;/p&gt;
&lt;p&gt;A database cluster that claims availability means that a large selection of nodes will need to be offline before you lose the ability to write and read a given piece of data. Generally databases with the availability claim work best when any given piece of data exists in multiple data-centers. An AP database also has partition-tolerance: the nodes can stop talking to each other, and your data is still there to read and write.&lt;/p&gt;
&lt;p&gt;As the CAP theorem implies, the big downside to AP database clusters is the lack of consistency. This means that for any given piece of data, you might get different results depending on which node you ask. Generally these databases gather results, so that each node will eventually all agree on multiple versions of the truth.&lt;/p&gt;
&lt;p&gt;This isn&apos;t as bad as it sounds.&lt;/p&gt;
&lt;p&gt;Lack of consistency happens in an AP cluster when a single piece of data has been written to in two different places, either in close proximity to time, or during a net-split (when the two nodes were unable to communicate due to network failure). Some databases have settings and even defaults for resolving these cases with the Last-Write-Wins solution. Keep in mind, however, that you&apos;re destroying data from a confirmed write.&lt;/p&gt;
&lt;p&gt;The best solution for lack of consistency is in your application itself, perhaps in the API service, for example. When you read a piece of data and get multiple results back, you should have a function for resolving consistency problems with that data-type. Merging the data, picking one over another, or creating a new data object are all possible solutions, and should be hand selected for each data type.&lt;/p&gt;
&lt;h2 id=&quot;hybrid-solutions&quot;&gt;&lt;a href=&quot;#hybrid-solutions&quot; aria-label=&quot;hybrid solutions permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Hybrid Solutions&lt;/h2&gt;
&lt;p&gt;In the end, you may want to mix a single state server, a CP cluster, and an AP cluster together for the different data types that you use. This hybrid approach can help you strike the right balance when your requirements are complicated by the limits of the CAP Theorem.&lt;/p&gt;
&lt;p&gt;Since this is my blog post, I&apos;ll tell you about my personal favorites:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standalone, non-clustered data, snapshot backups, slaving: Redis&lt;/li&gt;
&lt;li&gt;Consistent, partition-tolerant, high reads, low writes: Postgres&lt;/li&gt;
&lt;li&gt;Available, partition-tolerant, horizontal scaling: Riak&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&apos;m sure I&apos;ll have different favorites tomorrow. :-)&lt;/p&gt;
&lt;p&gt;I&apos;ve also been working on &lt;a href=&quot;https://github.com/fritzy/dulcimer&quot;&gt;Dulcimer&lt;/a&gt;, which &lt;a href=&quot;http://andyet.com&quot;&gt;&amp;#x26;yet&lt;/a&gt; uses to develop locally against an embedded leveldb, and deploy and scale against Riak (Postgres support is in progress). Dulcimer aims to be a single way of dealing with a wide variety of key-store technologies.&lt;/p&gt;
&lt;p&gt;In the end, choose the best tool for the job, and don&apos;t get wedded to any specific piece of technology.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If you have in-depth questions about choosing the right database for your needs, consider our &lt;a href=&quot;http://andyet.com/consulting/architecture&quot;&gt;architecture consulting services&lt;/a&gt;.  &lt;/p&gt;
&lt;p&gt;Feel free to comment directly to &lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;Nathan Fritz @fritzy&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Automated testing of WebRTC applications]]></title><description><![CDATA[As you probably know, we run Talky, a free videochat service powered by WebRTC. Since WebRTC is still evolving quickly, we add new features…]]></description><link>https://blog.andyet.com/2014/09/29/testing-webrtc-applications/</link><guid isPermaLink="false">https://blog.andyet.com/2014/09/29/testing-webrtc-applications/</guid><pubDate>Mon, 29 Sep 2014 09:30:00 GMT</pubDate><content:encoded>&lt;p&gt;As you probably know, we run &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt;, a free videochat service powered by WebRTC. Since WebRTC is still evolving quickly, we add new features to Talky roughly every two weeks. So far, this has required manual testing in Chrome, Opera, and Firefox each time to verify that the deployed changes are working. Since the goal of any deploy is to avoid breaking the system, each time we make a change we run it through a post-commit set of unit tests, as well as an integration test using a browser test-runner script as outlined in this post.&lt;/p&gt;
&lt;p&gt;All that manual testing is pretty old-fashioned, though. Since WebRTC is supposed to be for the web, we decided it was time to apply modern web testing methods to the problem.&lt;/p&gt;
&lt;p&gt;The trigger was reading two &lt;a href=&quot;http://googletesting.blogspot.se/2014/08/chrome-firefox-webrtc-interop-test-pt-1.html&quot;&gt;blog&lt;/a&gt; &lt;a href=&quot;http://googletesting.blogspot.se/2014/09/chrome-firefox-webrtc-interop-test-pt-2.html&quot;&gt;posts&lt;/a&gt; published recently by Patrik Höglund of the Google WebRTC team, describing how they do automated interop testing between Chrome and Firefox. This motivated me to spend some time on the post-deploy process of testing we do for Talky. The result is &lt;a href=&quot;https://github.com/otalk/webrtc-tester&quot;&gt;now available on github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&apos;s review how Talky works and what we need to test. Basically we need to verify that two browsers can connect to our signaling service and establish a direct connection. The test consists of three simple steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;determine a room name to test against by generating a random number to use for the room URL&lt;/li&gt;
&lt;li&gt;start two browsers&lt;/li&gt;
&lt;li&gt;determine that the peer-to-peer connection is up and that video is running.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the process fails in the staging area, our ops team will not deploy the new version to the main Talky site.&lt;/p&gt;
&lt;p&gt;Although step one is easy, starting the two browsers is more complicated. When a user goes directly to a videochat room we show a &quot;check-your-hair screen&quot; which requires a user action to join. It&apos;s already possible to skip this by using a localStorage javascript setting. This means we need to start both browsers with a clean profile and pre-seed the localStorage database with some of those settings.&lt;/p&gt;
&lt;p&gt;To get around all that manual testing, we want to run these tests on servers and machines that don&apos;t have any webcams and microphones attached. Fortunately, this is pretty easy to achieve because the browser manufacturers provide special ways to simulate webcams and microphones for testing purposes. In Chrome, this is done by adding &lt;code class=&quot;language-text&quot;&gt;--use-fake-device-for-media-stream&lt;/code&gt; as a command line argument when starting the browser. In Firefox, a special &lt;code class=&quot;language-text&quot;&gt;fake:true&lt;/code&gt; variable in the getUserMedia calls needs to be set (as explained &lt;a href=&quot;http://rtc.io/testing-process.html&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Since we don&apos;t want user interaction, we also need to do something similar for skipping the security prompt. In Chrome, that is achieved with the &lt;code class=&quot;language-text&quot;&gt;--use-fake-ui-for-media-stream&lt;/code&gt; flag; in Firefox, this is done with by setting a preference of &lt;code class=&quot;language-text&quot;&gt;media.navigator.permission.disabled:true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, we need to actually start the browsers in a way which doesn&apos;t require any visible windows and works on headless servers as well. Fortunately, there is a Linux tool for this called &lt;a href=&quot;http://en.wikipedia.org/wiki/Xvfb&quot;&gt;xvfb&lt;/a&gt;. It is even used by a &lt;a href=&quot;https://github.com/GoogleChrome/webrtc/tree/master/samples/web/content/apprtc/turn-prober&quot;&gt;sample script&lt;/a&gt; that is part of Google&apos;s &lt;a href=&quot;https://github.com/googlechrome/webrtc&quot;&gt;WebRTC code available on github&lt;/a&gt;. After starting two browsers, we need to wait for them to become connected. This is relatively easy to determine by listening for the iceconnectionstatechange events of the WebRTC peerconnection API. Check the &lt;a href=&quot;https://simplewebrtc.com/demo.html&quot;&gt;simplewebrtc demo page&lt;/a&gt; for a basic example.&lt;/p&gt;
&lt;p&gt;We wait for this event to happen and then write something to the logs. In Chrome this is relatively easy, since normal console.log calls will be written to the log file on disk. In Firefox this turned out to be slightly more complicated: we need to set a preference &lt;code class=&quot;language-text&quot;&gt;browser.dom.window.dump.enabled:true&lt;/code&gt; and then use a window.dump call to write something to the standard output. For Talky, we log the string &lt;code class=&quot;language-text&quot;&gt;P2P connected&lt;/code&gt;. Other applications, such as &lt;a href=&quot;https://github.com/jitsi/jitsi-meet&quot;&gt;Jitsi Meet&lt;/a&gt; can be tested that way as well. Our shell script then searches the logs for that string and if found, waits for another five seconds before declaring the test a success and exiting.&lt;/p&gt;
&lt;p&gt;Sounds pretty simple, eh? It&apos;s just putting a bunch of pieces together, building on the work Patrik Höglund has done and pushing it slightly further. The test saves us lots of time on each deploy and allows us to deploy changes to our &lt;a href=&quot;https://pro.talky.io/&quot;&gt;new talky.pro service&lt;/a&gt; without headache. We can even run it continuously to check whether our service is up. We&apos;re also integrating this technique into our software development process for all the &lt;a href=&quot;https://otalk.org/&quot;&gt;Otalk&lt;/a&gt; WebRTC modules. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Want to get started with WebRTC?  Check out our &lt;a href=&quot;https://andyet.com/consulting/webrtc&quot;&gt;WebRTC consulting services&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Comment directly to &lt;a href=&quot;https://twitter.com/HCornflower&quot;&gt;Philipp Hancke @HCornflower&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The thing you don't think about until you need it.]]></title><description><![CDATA[Next Tuesday, &yet is hosting a blood drive put on by the American Red Cross. For some, that's maybe the most boring sentence they've ever…]]></description><link>https://blog.andyet.com/2014/09/28/the-thing-you-dont-think-about/</link><guid isPermaLink="false">https://blog.andyet.com/2014/09/28/the-thing-you-dont-think-about/</guid><pubDate>Sun, 28 Sep 2014 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Next Tuesday, &lt;a href=&quot;http://andyet.com/&quot;&gt;&amp;#x26;yet&lt;/a&gt; is hosting a &lt;a href=&quot;https://www.facebook.com/events/877091552300926/&quot;&gt;blood drive&lt;/a&gt; put on by the &lt;a href=&quot;http://www.redcrossblood.org/&quot;&gt;American Red Cross&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;For some, that&apos;s maybe the most boring sentence they&apos;ve ever read. &lt;/p&gt;
&lt;p&gt;For others, who have been on a different side of that need, it&apos;s another chance.&lt;/p&gt;
&lt;p&gt;Chance? Need? Blood?&lt;/p&gt;
&lt;p&gt;For some just reading the word &quot;blood,&quot; or thinking about the fluid is enough to trigger some sort of uneasy &quot;I don&apos;t fill-in-blank well with blank&quot; reaction.&lt;/p&gt;
&lt;p&gt;Coming to terms with the reality of components within us that keep us alive and breathing can be a jarring experience for some.&lt;/p&gt;
&lt;p&gt;I&apos;m not sure why, but when confronted with images of blood or needles, I get a slightly warm, queasy feeling that I want to just push away from myself and ignore until homeostasis returns. If I had to guess, I would blame part of it on social conditioning to be made uncomfortable by things that in my experience have only held a very important and sterile place. &lt;/p&gt;
&lt;p&gt;But I think another part of it is being confronted with the reality that my life is finite. There are limited resources within my conscious being, keeping me alive. I could lose it all in an event completely out of my control, at any time. &lt;/p&gt;
&lt;p&gt;So yeah, thinking about blood makes me uncomfortable. I don&apos;t want to do it. &lt;/p&gt;
&lt;p&gt;However, I would argue that coming to terms with something more devastating, like the death of a loved one from loss or lack of those life sustaining components–like blood–is a far more traumatic experience. &lt;/p&gt;
&lt;p&gt;One I have had, repeatedly, from a disease called Leukemia. &lt;/p&gt;
&lt;p&gt;Leukemia started stealing family members from me in high school, starting with my grandfather. The pattern continued in college with the death of a beloved second cousin, &quot;Uncle&quot; Jim. He was the one who told me &quot;If you drink and drive, don&apos;t smoke — you gotta have one hand on the wheel.&quot;&lt;/p&gt;
&lt;p&gt;If you are unfamiliar with Leukemia, let me introduce you to it by saying it sucks. &lt;/p&gt;
&lt;p&gt;Leukemia is a cancer of the blood and blood cells, that comes in a variety of diseases. For more information on the illness, I&apos;ll let the good folks at the &lt;a href=&quot;http://www.lls.org/#/&quot;&gt;Leukemia and Lymphoma Society&lt;/a&gt; educate you in far more articulate and less emotionally charged terms on their site. &lt;/p&gt;
&lt;p&gt;(Interesting aside, only two percent of the American population donates blood regularly. If &lt;em&gt;one&lt;/em&gt; more percent began donating on a regular basis, it would irradicate the shortage of supply. Just one percent. And 38 percent of the population is eligible to donate, meaning they meet the donor requirements, but only 10 percent ever do.)&lt;/p&gt;
&lt;p&gt;Treatments for Leukemia include radiation, chemotherapy, anti-biotics and blood transfusions. Transfusions are often necessary because of the depleting effects the first two treatments above can have on a patient&apos;s blood supply. &lt;/p&gt;
&lt;p&gt;Transfusions give people time. Transfusions save lives. &lt;/p&gt;
&lt;p&gt;I know I&apos;m not saying anything you haven&apos;t heard before, but if you&apos;re like me, you&apos;re probably still somewhat hand wavy about feeling bad for that bad stuff that happens to people sometimes who are not you. &lt;/p&gt;
&lt;p&gt;True, Leukemia hasn&apos;t happened to me, personally. It did remove individuals from my life who I used to be able to see and talk with and hear their voices and feel their hugs and have their presence in my life. &lt;/p&gt;
&lt;p&gt;But, since these people are my family, I very well could have that sneaky genome for Leukemia lurking in my system, to someday steal me from my daughter, my family. And if that happens, I want to fight. I want more time. &lt;/p&gt;
&lt;p&gt;I like being alive. As I&apos;m guessing, most people do. &lt;/p&gt;
&lt;p&gt;I hardly ever think about how at least three pints are needed for a transfusion, and that in the event of an accident, if I&apos;m taken to the hospital, that those pints are already there on the shelf. &lt;/p&gt;
&lt;p&gt;Because someone made the conscious contribution to save my life. &lt;/p&gt;
&lt;p&gt;I&apos;m asking for your help in this. One pint of your blood has several different components and has the potential to save three lives. Three human beings. &lt;/p&gt;
&lt;p&gt;Sure it&apos;s uncomfortable, but it&apos;s an easy way to make the world a better place by giving the least of yourself so that someone else can live. &lt;/p&gt;
&lt;p&gt;Be a donor. &lt;/p&gt;
&lt;p&gt;If you&apos;re in the local Tri-Cities area, come to the &amp;#x26;yet office at 110 Gage Boulevard, Suite 100 in Richland, Washington this Tuesday, September 30 from 10 am to 3 pm. I will greet you at the door. &lt;/p&gt;
&lt;p&gt;If you&apos;re inspired to donate in your area, visit the American Red Cross at &lt;a href=&quot;http://www.redcrossblood.org/&quot;&gt;www.redcrossblood.org&lt;/a&gt; to find a drive or center in your area. (It&apos;s easy, I promise, there&apos;s a blue box at the top right hand corner that says &quot;Give Blood. Find a Blood Drive.&quot;)&lt;/p&gt;
&lt;p&gt;Every little bit counts.&lt;/p&gt;
&lt;p&gt;Thank you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[WebRTC platforms: there IS a better way]]></title><description><![CDATA[More and more application developers have come to rely on platform-as-a-service providers for building and scaling software.WebRTC's…]]></description><link>https://blog.andyet.com/2014/09/26/webrtc-platforms/</link><guid isPermaLink="false">https://blog.andyet.com/2014/09/26/webrtc-platforms/</guid><pubDate>Fri, 26 Sep 2014 10:30:00 GMT</pubDate><content:encoded>&lt;p&gt;More and more application developers have come to rely on platform-as-a-service providers for building and scaling software.&lt;/p&gt;
&lt;p&gt;WebRTC&apos;s complexity makes it ripe for this kind of approach, so it&apos;s no surprise that so many early WebRTC companies have been platform service providers. Unfortunately for customers, the nascent Rent-Your-WebRTC-Solution market has proven pretty unstable.&lt;/p&gt;
&lt;p&gt;News &lt;a href=&quot;http://blog.blackboard.com/our-latest-acquisition-revolutionizing-video-conferencing/&quot;&gt;came yesterday&lt;/a&gt; that yet another provider of WebRTC hosted services—in this case, &lt;a href=&quot;http://requestec.com/&quot;&gt;Requestec&lt;/a&gt;—has been acquired. We&apos;ve seen this movie before with &lt;a href=&quot;http://www.chriskranky.com/addlive-acquired/&quot;&gt;Snapchat&apos;s acquisition of AddLive&lt;/a&gt; and we&apos;ll probably &lt;a href=&quot;http://bloggeek.me/webrtc-tool-vendors-next-to-go/&quot;&gt;see it again&lt;/a&gt;, maybe multiple times.&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet, we&apos;ve been working steadily at creating open source software and approaches to infrastructure to help our clients avoid the volatile WebRTC rental market. &lt;/p&gt;
&lt;p&gt;We believe we can help use and create common standards while working collaboratively with a coalition of developers who want to push WebRTC forward in an open way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We&apos;re pretty old school. We believe that&apos;s the way the best parts of the web have always been, and if it&apos;s up to us, that&apos;s the way the web—including WebRTC—will always be.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As with any software, &lt;em&gt;yes&lt;/em&gt;, you could build your entire platform yourself—from frontend to backend, from clean-coded clients to sustainable ops, including scalable and secure signaling, NAT traversal, and media servers. But it&apos;s awfully expensive and time-consuming to do that, even if you can find folks who have strong competence in this field. (And we can vouch that it&apos;s not a trivial undertaking, because we&apos;ve spent a year and a half doing it!)&lt;/p&gt;
&lt;p&gt;So you could rent, you could build your own, or you could work with a technology team that has the following qualities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They&apos;re experts on all aspects of WebRTC&lt;/li&gt;
&lt;li&gt;They&apos;re veterans with many other realtime technologies&lt;/li&gt;
&lt;li&gt;They produce code libraries that are extremely easy to build upon&lt;/li&gt;
&lt;li&gt;They&apos;re dev-friendly, ops-knowledgeable, and totally approachable&lt;/li&gt;
&lt;li&gt;They&apos;re dedicated to teaching and open-sourcing everything they know&lt;/li&gt;
&lt;li&gt;They&apos;re even willing and able to help you run the platform yourself &lt;/li&gt;
&lt;li&gt;They&apos;re completely independent and bootstrapped so they&apos;ll never sell the company—period&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sounds like one of those gauzy dream sequences in a cheesy movie–the kind that&apos;s shown right before someone gets hit with a large dose of cold, hard reality.&lt;/p&gt;
&lt;p&gt;But this movie has a happy ending, because at &amp;#x26;yet we&apos;re just that kind of team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Want to write your own story when it comes to WebRTC?&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;We encourage you to embrace the &lt;a href=&quot;http://blog.andyet.com/2014/09/08/introducing-otalk&quot;&gt;open platform that is Otalk&lt;/a&gt;, check out our &lt;a href=&quot;https://andyet.com/consulting/webrtc&quot;&gt;WebRTC consulting services&lt;/a&gt;, and &lt;a href=&quot;mailto:contact@andyet.com&quot;&gt;drop us a line&lt;/a&gt; to start a conversation.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[For realtime apps, send hints not data]]></title><description><![CDATA[At &yet, we've always specialized in realtime web apps. We've implemented them in a wide variety of ways and we've consulted with numerous…]]></description><link>https://blog.andyet.com/2014/09/23/send-hints-not-data/</link><guid isPermaLink="false">https://blog.andyet.com/2014/09/23/send-hints-not-data/</guid><pubDate>Tue, 23 Sep 2014 16:30:00 GMT</pubDate><content:encoded>&lt;p&gt;At &amp;#x26;yet, we&apos;ve always specialized in realtime web apps. We&apos;ve implemented them in a wide variety of ways and we&apos;ve consulted with numerous customers to help them understand the challenges of building such apps. A key difference is that realtime apps need a way of updating the application without direct intervention from the user.&lt;/p&gt;
&lt;h2 id=&quot;growing-pains&quot;&gt;&lt;a href=&quot;#growing-pains&quot; aria-label=&quot;growing pains permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Growing Pains&lt;/h2&gt;
&lt;p&gt;What data you send, and how much you send, is completely contextual to the application itself. Your choice of transport (polling, long-polling, WebSockets, server-sent events, etc.) is inconsequential as far as updating the page is concerned. App experience and performance are all about the data.&lt;/p&gt;
&lt;p&gt;In our earliest experiments, we tightly coupled client logic with the updates, allowing the server side to orchestrate the application entirely. This seems rather &quot;cool,&quot; but it ends up being a pain due to lack of separation of concerns. Having a tightly-coupled relationship between client and server means a lot of back and forth, nearly infinite amounts of pain (especially with flaky connections), and too much application orchestration logic.&lt;/p&gt;
&lt;p&gt;We moved on to simply giving the new data to the client when things changed, which removed all of the orchestration pain and gave more control to the application. Even this had some interesting pain points when dealing with shifts from offline to online, cache control, and lack of control over memory. Here are some of the problems we ran into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When replaying events after a reconnect, the service had to remember what should have been sent, in what order, for that user specifically.&lt;/li&gt;
&lt;li&gt;Similar issues arose when switching subscription states on data.&lt;/li&gt;
&lt;li&gt;Applications that simply couldn&apos;t handle all of the data being loaded into the app at once had a lot of timing issues with updates and API calls.&lt;/li&gt;
&lt;li&gt;If your permissions were tricky, pushes became an extra place that they had to be checked.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;getting-the-hint&quot;&gt;&lt;a href=&quot;#getting-the-hint&quot; aria-label=&quot;getting the hint permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Getting the Hint&lt;/h2&gt;
&lt;p&gt;Eventually we realized all of these problems could be solved with &lt;em&gt;hinting&lt;/em&gt;. Rather than sending the data, we send the data type, the ID, and whether it was an update, a delete, or new data. The application then requests the data it cares about - and only the data it cares about - from the HTTP API.&lt;/p&gt;
&lt;p&gt;Now after a reconnect, we can query for a set of IDs that have changed since that time plus some extra for good measure, without caring about order at all. Since all of the data comes from the API, we don&apos;t have timing issues with API data versus update data, and we have a single source of truth and a true separation of concerns. The application can now keep caches, and mark the cached data as dirty or delete it accurately over time, whether the data is being displayed or just kept handy.&lt;/p&gt;
&lt;p&gt;All-in-all, simply hinting data changes removes a lot of tricky edge cases, and empowers the application developer to control their data effectively. Hinting FTW!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We can help you &lt;a href=&quot;http://andyet.com/consulting/architecture&quot;&gt;leverage our expertise on architecture&lt;/a&gt;.&lt;br&gt;
Feel free to comment directly to &lt;a href=&quot;https://twitter.com/fritzy&quot;&gt;Nathan Fritz @fritzy&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Helping Docker get along with iptables]]></title><description><![CDATA[On the &yet Ops Team, we use Docker for various purposes on some of the servers we run. We also make extensive use of iptables so that we…]]></description><link>https://blog.andyet.com/2014/09/11/docker-host-iptables-forwarding/</link><guid isPermaLink="false">https://blog.andyet.com/2014/09/11/docker-host-iptables-forwarding/</guid><pubDate>Thu, 11 Sep 2014 16:30:00 GMT</pubDate><content:encoded>&lt;p&gt;On the &amp;#x26;yet Ops Team, we use &lt;a href=&quot;http://docker.com&quot;&gt;Docker&lt;/a&gt; for various purposes on some of the servers we run. We also make &lt;a href=&quot;https://blog.andyet.com/2014/09/09/taming-iptables&quot;&gt;extensive use of iptables&lt;/a&gt; so that we have consistent firewall rules to protect those servers against attacks. &lt;/p&gt;
&lt;p&gt;Unfortunately, we recently ran into an issue that prevented us from building &lt;a href=&quot;http://docs.docker.com/reference/builder/&quot;&gt;Dockerfiles&lt;/a&gt; from behind an iptables firewall. &lt;/p&gt;
&lt;p&gt;Here&apos;s a bit more information about the problem, and how we solved it.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;&lt;a href=&quot;#the-problem&quot; aria-label=&quot;the problem permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Problem&lt;/h2&gt;
&lt;p&gt;When trying to run &lt;code class=&quot;language-text&quot;&gt;docker build&lt;/code&gt; on a host that provides our default DROP policy-based iptables set, &lt;code class=&quot;language-text&quot;&gt;apt-get&lt;/code&gt; was unable to resolve repository hosts on Dockerfiles that were &lt;code class=&quot;language-text&quot;&gt;FROM&lt;/code&gt; Ubuntu or debian. &lt;/p&gt;
&lt;p&gt;Any &lt;code class=&quot;language-text&quot;&gt;apt-get&lt;/code&gt; command would result in something like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Step 1 : RUN apt-get update
 ---&amp;gt; Running in 64a37c06d1f4
Err http://http.debian.net wheezy Release.gpg
  Could not resolve &amp;#39;http.debian.net&amp;#39;
Err http://http.debian.net wheezy-updates Release.gpg
  Could not resolve &amp;#39;http.debian.net&amp;#39;
Err http://security.debian.org wheezy/updates Release.gpg
  Could not resolve &amp;#39;security.debian.org&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To figure out what was going wrong, we logged all dropped packets in iptables to syslog like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;# Log dropped outbound packets
iptables -N LOGGING
iptables -A OUTPUT -j LOGGING
iptables -A INPUT -j LOGGING
iptables -A FORWARD -j LOGGING
iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix &amp;quot;IPTables-Dropped: &amp;quot; --log-level 4
iptables -A LOGGING -j DROP&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The logs quickly showed that the &lt;code class=&quot;language-text&quot;&gt;docker0&lt;/code&gt; interface was trying to FORWARD port 53 to the &lt;code class=&quot;language-text&quot;&gt;eth0&lt;/code&gt; interface. In our case, the default FORWARD policy is DROP, so essentially iptables was dropping Docker&apos;s requests to forward the DNS port to the public interface and Internet at large. &lt;/p&gt;
&lt;p&gt;Since Docker couldn&apos;t resolve the domain names where the Dockerfiles were located, it couldn&apos;t retrieve the data it needed.&lt;/p&gt;
&lt;h2 id=&quot;a-solution&quot;&gt;&lt;a href=&quot;#a-solution&quot; aria-label=&quot;a solution permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A Solution&lt;/h2&gt;
&lt;p&gt;Hmm, so we needed to allow forwarding between &lt;code class=&quot;language-text&quot;&gt;docker0&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;eth0&lt;/code&gt; , eh? That&apos;s easy! We just added the following rules to our iptables set:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;# Forward chain between docker0 and eth0
iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o docker0 -j ACCEPT

# IPv6 chain if needed
ip6tables -A FORWARD -i docker0 -o eth0 -j ACCEPT
ip6tables -A FORWARD -i eth0 -o docker0 -j ACCEPT&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Add or alter these rules as needed, and you too will be able to build Dockerfiles properly behind an iptables firewall.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Tao of Ops: Taming iptables]]></title><description><![CDATA[One of the best tools to use every day for locking down your servers is iptables. (You do lock down your servers, right? ;-)Not using…]]></description><link>https://blog.andyet.com/2014/09/09/taming-iptables/</link><guid isPermaLink="false">https://blog.andyet.com/2014/09/09/taming-iptables/</guid><pubDate>Tue, 09 Sep 2014 12:42:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the best tools to use every day for locking down your servers is iptables. (You do lock down your servers, right? ;-)&lt;/p&gt;
&lt;p&gt;Not using iptables is akin to having fancy locks with a plywood door - sure it is secure but you just cannot &lt;em&gt;know&lt;/em&gt; that someone won’t be able to break through.&lt;/p&gt;
&lt;p&gt;To this end I use a small set of bash scripts that ensure I always have a baseline iptables configuration and items can be added or removed quickly.&lt;/p&gt;
&lt;p&gt;Let me outline what they are before we get to the fiddly bits...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;checkiptables.sh — A script to compare your saved iptables config in /etc/iptables.rules to what is currrently being used. &lt;em&gt;Very&lt;/em&gt; handy to see if you have any local changes before modifying the global config.&lt;/li&gt;
&lt;li&gt;iptables-pre-up — A Debian/Ubuntu centric script that runs when your network interface comes online to ensure that your rules are active on restart. RedHat/CentOS folks don’t need this.&lt;/li&gt;
&lt;li&gt;iptables.sh — The master script that sets certain defaults and then loads any inbound/outbound scripts.&lt;/li&gt;
&lt;li&gt;iptables_*.sh — A bash scripts that is very easy to generate using templates for each rule needed to allow inbound/outbound traffic. I use a naming pattern to make them unique within the directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These scripts should be placed into your favourite local binary directory, for example&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/opt/sbin
  /checkiptables.sh
  /iptables.sh
  /iptables_conf.d/
    iptables_*.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;checkiptables.sh&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# generate a list of active rules and remove all the cruft&lt;/span&gt;
iptables-save &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; -e ’/^&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;#:]/d’ &gt; /tmp/iptables.check&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; -e /etc/iptables.rules &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; /etc/iptables.rules &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; -e ’/^&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;#:]/d’ &gt; /tmp/iptables.rules&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;diff&lt;/span&gt; -q /tmp/iptables.rules /tmp/iptables.check
&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;unable to check, /etc/iptables.rules does not exist&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That is really it - the magic is in the sed portion - it removes all of the stuff that iptables-save outputs that isn’t related to rules and often can change between runs. The remainder of the script is performing a diff against the saved state vs current state. If current state has been modified you will see as output:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Files /tmp/iptables.rules and /tmp/iptables.check differ&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;iptables.sh&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/bin/bash&lt;/span&gt;
PUBLICNET&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;eth2

iptables -F
ip6tables -F
ip6tables -X
ip6tables -t mangle -F
ip6tables -t mangle -X

&lt;span class=&quot;token comment&quot;&gt;# Default policy is drop&lt;/span&gt;
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
ip6tables -P FORWARD DROP

iptables -A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh
iptables -A fail2ban-ssh -j RETURN
&lt;span class=&quot;token comment&quot;&gt;# Allow localhost&lt;/span&gt;
iptables -A INPUT  -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
ip6tables -A INPUT  -i lo -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT
&lt;span class=&quot;token comment&quot;&gt;# Allow inbound ipv6 ICMP so we can be seen by neighbors&lt;/span&gt;
ip6tables -A INPUT  -i &lt;span class=&quot;token variable&quot;&gt;${PUBLICNET}&lt;/span&gt; -p ipv6-icmp -j ACCEPT
ip6tables -A OUTPUT -o &lt;span class=&quot;token variable&quot;&gt;${PUBLICNET}&lt;/span&gt; -p ipv6-icmp -j ACCEPT
&lt;span class=&quot;token comment&quot;&gt;# Allow incoming SSH&lt;/span&gt;
iptables -A INPUT  -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
&lt;span class=&quot;token comment&quot;&gt;# Allow outbound DNS&lt;/span&gt;
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT  -p udp --sport 53 -j ACCEPT
&lt;span class=&quot;token comment&quot;&gt;# Only allow NTP if it’s our request&lt;/span&gt;
iptables -A INPUT -s 0/0 -d 0/0 -p udp --source-port 123:123 -m state --state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -s 0/0 -d 0/0 -p udp --destination-port 123:123 -m state --state NEW,ESTABLISHED -j ACCEPT

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; s &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; /opt/sbin/iptables_conf.d/iptables_*.sh &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; -e &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${s}&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;${s}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There is a lot going on here - flushing all current rules, setting the default policy to DROP so nothing gets through until you explicitly allow it and then allowing all localhost traffic.&lt;/p&gt;
&lt;p&gt;After the boilerplate code, the remainder is setting up rules for SSH, DNS and other ports that are common to all server deploys. It’s the last five lines where the fun is - they loop through the files found in the iptables_conf.d directory and load any iptables_*.sh script they find. Here’s an example rule that would be in iptables_conf.d/ - this one allows outbound Etcd:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Allow outgoing etcd&lt;/span&gt;
iptables -A OUTPUT -o eth2 -p tcp --dport 4001 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT  -i eth2 -p tcp --sport 4001 -m state --state ESTABLISHED -j ACCEPT&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Having each rule defined by a script allows you to create the scripts using templates from your configuration system.&lt;/p&gt;
&lt;p&gt;With the above you now have a very flexible way to manage iptables that is also self-documenting - how cool is that!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing Otalk, an easy and open way to build collaboration apps]]></title><description><![CDATA[Building collaboration apps has always been too hard, especially when audio and video are involved. The promise of WebRTC - building audio…]]></description><link>https://blog.andyet.com/2014/09/08/introducing-otalk/</link><guid isPermaLink="false">https://blog.andyet.com/2014/09/08/introducing-otalk/</guid><pubDate>Mon, 08 Sep 2014 09:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Building collaboration apps has always been too hard, especially when audio and video are involved. The promise of &lt;a href=&quot;http://webrtc.org/&quot;&gt;WebRTC&lt;/a&gt; - building audio and video support directly into the browser - has been that it would make collaboration as easy and open as the web itself. Unfortunately, that hasn&apos;t quite happened yet. &lt;/p&gt;
&lt;p&gt;A big part of the problem is that we lack the kind of open platforms and frameworks that have made the web such a success - things like, say, &lt;a href=&quot;http://expressjs.com/&quot;&gt;express&lt;/a&gt; and &lt;a href=&quot;http://hapijs.com/&quot;&gt;hapi&lt;/a&gt; in the Node.js community. Instead of open standards and open source, web developers coming to the collaboration space find themselves faced with a plethora of proprietary platforms tied to specific vendors. &lt;/p&gt;
&lt;p&gt;Don&apos;t get us wrong: some of those platforms are excellent. However, if you&apos;re dependent on a particular service provider for the platform that powers your entire real-time collaboration app then you&apos;ve taken on some &lt;a href=&quot;http://www.chriskranky.com/can-trust-webrtc-service/&quot;&gt;significant risks&lt;/a&gt;. Vendor lock-in and high switching costs are two that come quickly to mind. Not to mention the possibility that the startup service you depend on will go out of business, get bought by one of your competitors, or be taken off the market by an acquiring company.&lt;/p&gt;
&lt;p&gt;That&apos;s not a recipe for happy application developers.&lt;/p&gt;
&lt;p&gt;We&apos;re working to change that by creating a completely open set of front-end libraries and back-end services we&apos;re calling &lt;a href=&quot;http://otalk.org&quot;&gt;Otalk&lt;/a&gt;. The goal is to create a &quot;soup to nuts&quot; technology base that we can run for ourselves (since it&apos;s the basis for our &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; videochat service), that we can offer to organizations building their own realtime applications, and that other organizations can take in-house at any time (since it&apos;s completely open-source).&lt;/p&gt;
&lt;p&gt;Why would we do this? Why not build yet another silo and reap the benefits?&lt;/p&gt;
&lt;p&gt;First, we care deeply about the open web and we have a long-time commitment to open-source technologies because we believe they&apos;re more sustainable and more secure. Openness is at the very heart of our values as a team.&lt;/p&gt;
&lt;p&gt;Second, we&apos;re a fully bootstrapped company and we don&apos;t have any investors to please, so locking in developers isn&apos;t something we need to do for the next funding round or to sell the company.&lt;/p&gt;
&lt;p&gt;Third, we tend to make money through consulting, training, and custom app development. The more that folks use the Otalk platform, the bigger the potential market for our core services.&lt;/p&gt;
&lt;p&gt;Fourth, we&apos;re running Otalk anyway as the foundation for collaboration apps like Talky. Why not offer it to the world so that web developers everywhere can more easily build their own applications?&lt;/p&gt;
&lt;p&gt;Right now we&apos;re using a particular technology stack: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;XMPP over WebSockets for signaling using &lt;a href=&quot;https://prosody.im/&quot;&gt;Prosody&lt;/a&gt; on the back end &lt;/li&gt;
&lt;li&gt;along with JS-friendly code like &lt;a href=&quot;https://github.com/otalk/stanza.io&quot;&gt;stanza.io&lt;/a&gt; for the web, &lt;/li&gt;
&lt;li&gt;and libraries that we&apos;re working on with &lt;a href=&quot;http://steamclock.com/&quot;&gt;Steamclock&lt;/a&gt; for mobile; &lt;/li&gt;
&lt;li&gt;and media bridging for improved scalability using the &lt;a href=&quot;https://jitsi.org/Projects/JitsiVideobridge&quot;&gt;Jitsi Videobridge&lt;/a&gt;; &lt;/li&gt;
&lt;li&gt;also STUN and TURN for NAT traversal using &lt;a href=&quot;http://www.creytiv.com/restund.html&quot;&gt;restund&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(More about those pieces and how they fit together in future blog posts.)&lt;/p&gt;
&lt;p&gt;Much as we like this approach, we recognize that not everyone is &lt;a href=&quot;https://blog.andyet.com/2014/08/27/what-weve-learned-from-15-years-of-signaling&quot;&gt;sold on XMPP&lt;/a&gt; or the particular implementations we use. Thus we&apos;re also actively investigating ways to make Otalk more modular, so that you could use, say, SIP for signaling, your preferred STUN/TURN server, or a third-party media bridging service. Just want to use our developer-friendly front-end libraries like &lt;a href=&quot;https://simplewebrtc.com/&quot;&gt;SimpleWebRTC&lt;/a&gt; with your existing platform? Let&apos;s make it happen! Oh, and we&apos;re working to standardize a few XMPP extensions for multi-party signaling  and such, so that the entire &lt;a href=&quot;http://xmpp.org/&quot;&gt;XMPP community&lt;/a&gt; can play in the realtime collaboration space. &lt;/p&gt;
&lt;p&gt;As you can see, we&apos;re already working with with multiple teams to make Otalk a reality. But we need your help to make it a real success. &lt;/p&gt;
&lt;p&gt;Of course, developers are welcome to contribute via the &lt;a href=&quot;https://github.com/otalk&quot;&gt;Otalk org at GitHub&lt;/a&gt;. Dive right in!&lt;/p&gt;
&lt;p&gt;Perhaps even more important are organizations who require realtime technologies they can build upon in a sustainable way over the long term. Together, we&apos;re stronger than we could ever be apart. If you would like to partner with us or if have any questions about the emerging Otalk coalition, please &lt;a href=&quot;mailto:projects-webrtc@andyet.net&quot;&gt;drop us a line&lt;/a&gt; and we&apos;ll get right back to you.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;3&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Need help with WebRTC? &lt;a href=&quot;https://andyet.com/consulting/webrtc&quot;&gt;Tap into our expertise&lt;/a&gt;.&lt;br&gt;
Feel free to comment directly to &lt;a href=&quot;https://twitter.com/stpeter&quot;&gt;Peter Saint-Andre @stpeter&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[What we've learned from 15 years of signaling]]></title><description><![CDATA[About a year ago, our friends at TokBox published a blog post entitled WebRTC and Signaling: What Two Years Has Taught Us.  It's a great…]]></description><link>https://blog.andyet.com/2014/08/27/what-weve-learned-from-15-years-of-signaling/</link><guid isPermaLink="false">https://blog.andyet.com/2014/08/27/what-weve-learned-from-15-years-of-signaling/</guid><pubDate>Wed, 27 Aug 2014 13:56:00 GMT</pubDate><content:encoded>&lt;p&gt;About a year ago, our friends at &lt;a href=&quot;http://tokbox.com/&quot;&gt;TokBox&lt;/a&gt; published a blog post entitled &lt;a href=&quot;http://www.tokbox.com/blog/webrtc-and-signaling-what-two-years-has-taught-us/&quot;&gt;WebRTC and Signaling: What Two Years Has Taught Us&lt;/a&gt;.  It&apos;s a great overview of their experience with technologies like SIP and XMPP for stitching together WebRTC endpoints. And we couldn&apos;t agree more with their observation that trying to settle on one signaling method for WebRTC would have been even more contentious than the endless video codec debates. However, our experience with XMPP differs enough from theirs that we thought it would be good to set our thoughts down in writing.&lt;/p&gt;
&lt;p&gt;First, we&apos;re always a bit suspicious when someone says they abandoned XMPP because it didn&apos;t scale for them.  As a general rule, protocols don&apos;t scale - implementations do. We know of several XMPP server implementations that can route, distribute, and deliver tens of thousands of messages per second without breaking a sweat.  After all, that&apos;s what a messaging server is designed to do. Sure, some server implementations don&apos;t scale up that high; the answer is to use a better server. We&apos;re partial to &lt;a href=&quot;https://prosody.im/&quot;&gt;Prosody&lt;/a&gt;, but &lt;a href=&quot;http://tigase.org/&quot;&gt;Tigase&lt;/a&gt; and a few others are well worth researching, too.&lt;/p&gt;
&lt;p&gt;Second, pure messaging is the easy part. The hard part is defining the payloads for those messages to build out a wide variety of features and functionality. What we like best about the XMPP community is that over the last 15 years they have defined just about everything you need for a modern collaboration system: presence, contact lists, 1:1 messaging, group messaging, pubsub notifications, service discovery, device capabilities, strong authentication and encryption, audio/video session negotiation, file transfer, you name it. Why put a lot of work into recreating those wheels when they&apos;re ready-made for you?&lt;/p&gt;
&lt;p&gt;An added benefit of having so many building blocks is that it&apos;s straightforward to put them all together in productive ways. For example, XMPP includes extensions for both &lt;a href=&quot;http://xmpp.org/extensions/xep-0045.html&quot;&gt;multi-user chat&lt;/a&gt; (&quot;MUC&quot;) and &lt;a href=&quot;http://xmpp.org/extensions/xep-0166.html&quot;&gt;multimedia session management&lt;/a&gt; (Jingle). If we need multiparty signaling for video conferencing, we can easily combine the two to create what we need. Plus we get a number of advanced solutions for free this way, since MUC includes in-room presence along with a helpful authorization model and Jingle supports helpful features like renegotiation and file transfer. Not to mention that the ability to communicate device capabilities in XMPP enables us to avoid monstrosities like &lt;a href=&quot;https://datatracker.ietf.org/doc/draft-ietf-mmusic-sdp-bundle-negotiation/&quot;&gt;SDP bundling&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yes, we know: angle brackets. Web developers hate &apos;em. That&apos;s why we&apos;ve put so much work into making XMPP love the web, with open-source code like &lt;a href=&quot;http://www.stanza.io/&quot;&gt;stanza.io&lt;/a&gt; and &lt;a href=&quot;https://github.com/otalk/jingle.js&quot;&gt;jingle.js&lt;/a&gt; that communicates over the &lt;a href=&quot;http://datatracker.ietf.org/doc/draft-ietf-xmpp-websocket/&quot;&gt;WebSocket binding for XMPP&lt;/a&gt; (co-authored by yeti &lt;a href=&quot;https://andyet.com/team/lance&quot;&gt;Lance Stout&lt;/a&gt;). This gives us a completely web-developer-friendly technology for everything we need to build performant, feature-rich, and beautiful collaboration apps for the web. &lt;/p&gt;
&lt;p&gt;A perfect example close to our hearts is &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt;, our video chat service. The next generation of Talky will be based on XMPP, enabling us to easily build a wide range of similar applications by mixing and matching various XMPP features and extensions. But more about that in our next post...&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Opinionated rundown of JS frameworks]]></title><description><![CDATA[As a portion of our elaborate training events I give a short talk about JS frameworks. I've shied away from posting many of my opinions…]]></description><link>https://blog.andyet.com/2014/08/13/opinionated-rundown-of-js-frameworks/</link><guid isPermaLink="false">https://blog.andyet.com/2014/08/13/opinionated-rundown-of-js-frameworks/</guid><pubDate>Wed, 13 Aug 2014 10:34:35 GMT</pubDate><content:encoded>&lt;p&gt;As a portion of &lt;a href=&quot;http://andyet.com/training/human-javascript-live&quot;&gt;our elaborate training events&lt;/a&gt; I give a short talk about JS frameworks. I&apos;ve shied away from posting many of my opinions about frameworks online because it tends to stir the pot, hurt people&apos;s feelings, and unlike talking face to face, there&apos;s no really great, bi-directional channel for rebuttals.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;But&lt;/em&gt;, I&apos;ve been told that it was very useful and helped provide a nice, quick overview of some of the most popular JS tools and frameworks for building single page apps. So, I decided to flesh it out and publish it as A Thing™ but &lt;strong&gt;please remember that you&apos;re just reading opinions, I&apos;m not telling you what to do and you should do what works for you and your team&lt;/strong&gt;.  Feel free to disagree with me &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;on twitter&lt;/a&gt; or even better, write a post explaining your position.&lt;/p&gt;
&lt;h2 id=&quot;angularjs&quot;&gt;&lt;a href=&quot;#angularjs&quot; aria-label=&quot;angularjs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Angular.js&lt;/h2&gt;
&lt;h3 id=&quot;pros&quot;&gt;&lt;a href=&quot;#pros&quot; aria-label=&quot;pros permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;pros&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Super easy to start. You just drop in a script tag into your document add some &lt;code class=&quot;language-text&quot;&gt;ng-&lt;/code&gt; attributes to your app and you magically get behavior. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It&apos;s well-supported by a core team, many of whom are full time Google employees.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Big userbase / community.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;cons&quot;&gt;&lt;a href=&quot;#cons&quot; aria-label=&quot;cons permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;cons&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Picking Angular means you&apos;re learning Angular the framework instead of how to solve problems in JavaScript. If I were to encourage our team to build apps using Angular, what happens when {insert hot new JS framework} comes along? Or we discover that for a certain need, Angular can&apos;t quite do the thing we want it to and we want to build it with something else? At that point how well will those angular skills translate to something else? Instead, I&apos;ve got developers who&apos;s primary skill is Angular, not necessarily JavaScript.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Violates separation of concerns. Call me old school, but I still believe CSS is for style, HTML is for structure, and JavaScript is for app logic. But, in Angular you spend a lot of time describing behavior in HTML instead of JS. For me personally, this is the deal breaker with Angular. I don&apos;t want to describe application logic in HTML, it&apos;s simply not expressive enough because it&apos;s a markup language for structuring documents, not describing application logic. To get around this, Angular has had to create what is arguably another language inside HTML and then also writing a bit of JS to describe additional details. Now, rather than learning how to build applications in JavaScript, you&apos;re learning Angular and things seem to have a tendency to get complex. That&apos;s why &lt;a href=&quot;https://www.ng-book.com/&quot;&gt;my friend Ari&apos;s Angular book&lt;/a&gt; is 600 pages!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Too much magic. Magic comes at a cost. When you&apos;re working with something that&apos;s highly abstracted, it becomes a lot more difficult to figure out what&apos;s wrong when something goes awry. And of course, when you veer off the beaten path, you&apos;re on your own. I could be wrong, but I would guess most Angular users lack enough understanding of the framework itself to really feel confident modifying or debugging Angular itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provides very little structure. I&apos;m not sure a canonical way to build a single page app in Angular exists. Don&apos;t get me wrong, I think that&apos;s fine, there&apos;s nothing wrong with non-prescriptive toolkits but it does mean that it&apos;s harder to jump into someone else&apos;s angular app, or add someone to yours, because styles are likely very different.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;my-fallible-conclusion&quot;&gt;&lt;a href=&quot;#my-fallible-conclusion&quot; aria-label=&quot;my fallible conclusion permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;my fallible conclusion&lt;/h3&gt;
&lt;p&gt;There&apos;s simply too much logic described in a quasi-language in HTML rather than in JS and it all feels too abstract and too magical.&lt;/p&gt;
&lt;p&gt;I&apos;d rather our team get good at JS and DOM instead of learning a high-level abstraction.&lt;/p&gt;
&lt;h2 id=&quot;emberjs&quot;&gt;&lt;a href=&quot;#emberjs&quot; aria-label=&quot;emberjs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Ember.js&lt;/h2&gt;
&lt;h3 id=&quot;pros-1&quot;&gt;&lt;a href=&quot;#pros-1&quot; aria-label=&quot;pros 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;pros&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Heavy emphasis on doing things &quot;The Ember Way&quot; (also note item #1 in the &quot;cons&quot; section). This is a double edged sword. If you have a huge team and expect lots of churn, having rigid structure can be the difference between having a transferrable codebase and every new developer wanting to throw it all away. If they are all Ember devs, they can probably jump in and help on an Ember project. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Outsource many of the hard problems of building single page apps to some incredibly smart people who will make a lot of the hard tradeoff decisions for you. (also note item #2 in the &quot;cons&quot; section.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Big, helpful community.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nice docs site.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A good amount of existing solved problems and components to use.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;cons-1&quot;&gt;&lt;a href=&quot;#cons-1&quot; aria-label=&quot;cons 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;cons&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Heavy emphasis on doing things &quot;The Ember Way&quot;. Note this is also in the &quot;pros&quot; section. It&apos;s very prescriptive. While you &lt;em&gt;can&lt;/em&gt; veer from the standard path from the sound of it, many do not. For example, you don&apos;t &lt;em&gt;have&lt;/em&gt; to use handlebars with Ember, but I would be surprised if there are many production Ember apps out there that don&apos;t. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ember codifies a lot of opinions. If you don&apos;t agree with those opinions and decide to replace pieces of functionality with your own, you&apos;re still sending all the unused code to the browser. Byte counting isn&apos;t a core value of mine, but conceptually it&apos;s nicer to be able to only send what you use. In addition, when you&apos;re only sending what you&apos;re using, there&apos;s less code to sift through to locate the bug.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Memory usage can be a bit of an issue, which can be a problem, especially when &lt;a href=&quot;http://discuss.emberjs.com/t/ember-memory-consumption/528/3&quot;&gt;running Ember on mobile&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ember is intentionally, and structurally inflexible. Don&apos;t believe me? &lt;a href=&quot;https://twitter.com/wycats/status/446520058848624640&quot;&gt;Take Yehuda&apos;s word for it instead&lt;/a&gt; (the surrounding conversation is interesting too).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;my-fallible-conclusion-1&quot;&gt;&lt;a href=&quot;#my-fallible-conclusion-1&quot; aria-label=&quot;my fallible conclusion 1 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;my fallible conclusion&lt;/h3&gt;
&lt;p&gt;The lack of flexibility and feeling like in order to use Ember you have to go all or nothing is a deal breaker for me.&lt;/p&gt;
&lt;h2 id=&quot;react&quot;&gt;&lt;a href=&quot;#react&quot; aria-label=&quot;react permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;React&lt;/h2&gt;
&lt;p&gt;It&apos;s worth noting that it&apos;s not really fair to include React in this list. It&apos;s not a framework, it&apos;s a view layer. But there&apos;s so much discussion on this that I decided to add it here anyway. Arguably, when you mix in Facebook&apos;s flux dispatcher stuff, it&apos;s more of a framework.&lt;/p&gt;
&lt;h3 id=&quot;pros-2&quot;&gt;&lt;a href=&quot;#pros-2&quot; aria-label=&quot;pros 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;pros&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Blindly re-render without worrying about DOM thrashing, it will &quot;diff&quot; the virtual DOM that you render to, against what it knows the DOM is and will perform minimal changes to get them in sync.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Their virtual DOM also resolves issues with eventing across browsers by abstracting it to a standards-compliant event-emitting/bubbling model. As a result, you get a consistent event model across any browser. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It&apos;s just a view layer, not a complete framework. This means you can use it with whatever application orchestration you&apos;d like to do. It does seem to pair nicely with Backbone, since Backbone doesn&apos;t give you a view binding solution out of the box and encourages you to simply re-render on model changes, which is exactly what React encourages and deals with.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;cons-2&quot;&gt;&lt;a href=&quot;#cons-2&quot; aria-label=&quot;cons 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;cons&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The template syntax and the way you create DOM (with JSX) is a bit odd for a JS developer because you put unquoted HTML right into your Javascript as if it were valid to do so. And yes, JSX is optional, but the alternative: &lt;code class=&quot;language-text&quot;&gt;React.DOM.div(null, &amp;quot;Hello &amp;quot;, this.props.name);&lt;/code&gt; isn&apos;t much better, IMO. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you want really finite and explicit control over how things get applied to the DOM you don&apos;t really have it anymore. For example, if you want very specific control over how things are bound to style attributes, for creating touch draggable UIs. You can&apos;t easily time the order of how classes get applied, etc. (&lt;em&gt;please note&lt;/em&gt; this is something I&apos;ve assumed would be an issue but have not run into myself, but this was confirmed by a dev I was talking to who was struggling with exactly this. But take it with a grain of salt).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;While you can just re-render the entire react view, depending on the complexity of component, it sure seems like there can be a lot of diffing to do. I&apos;ve heard of React devs choosing to update only the known changed components, which to me, takes away from the whole idea of not having to care. Again, note that I&apos;m speaking from very limited experience.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;my-fallible-conclusion-2&quot;&gt;&lt;a href=&quot;#my-fallible-conclusion-2&quot; aria-label=&quot;my fallible conclusion 2 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;my fallible conclusion&lt;/h3&gt;
&lt;p&gt;I think React is very cool. If I had to build a single page app that supported old browsers I&apos;d look closely at using Backbone + React. &lt;/p&gt;
&lt;p&gt;A note on the &quot;FLUX&quot; architecture: To me this is not new information or even a new idea, just a new name. Apparently &lt;a href=&quot;https://twitter.com/jashkenas/status/497062452195250176&quot;&gt;I&apos;m not alone in that opinion&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;The way I understand it, conceptually FLUX is the same as having an intelligently evented model layer in something like Ampersand or Backbone and turning all user actions and server data updates into changes to that state. &lt;/p&gt;
&lt;p&gt;By ensuring that the user actions never result in directly manipulating the DOM you end up with the same unidirectional event propagation flow as FLUX + React. We intentionally didn&apos;t include any sort of two-way bindings in Ampersand for that reason. In my opinion two-way bindings are fraught with peril. Having a single layer deal with incoming events, be they from the server or user action is what we&apos;ve been doing for years.&lt;/p&gt;
&lt;h2 id=&quot;polymer&quot;&gt;&lt;a href=&quot;#polymer&quot; aria-label=&quot;polymer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Polymer&lt;/h2&gt;
&lt;p&gt;This one is a bit strange to me. There&apos;s a standard being developed for being able to define custom elements (&lt;code class=&quot;language-text&quot;&gt;document.registerElement&lt;/code&gt; for creating new HTML tags with built in behavior), doing HTML imports (&lt;code class=&quot;language-text&quot;&gt;&amp;lt;link type=&amp;#39;html&amp;#39;&amp;gt;&lt;/code&gt; for being able to import those custom elements into other documents), and shadow DOM (for isolating CSS from the rest of the document). &lt;/p&gt;
&lt;p&gt;Those things are great (except HTML imports, IMO). &lt;/p&gt;
&lt;p&gt;But, judging by Polymer&apos;s introduction, it sounds like a panacea for making all web development easy and amazing and that it&apos;s good for everything. Here&apos;s what the opening line says: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Web Components usher in a new era of web development based on encapsulated and interoperable custom elements that extend HTML itself. Built atop these new standards, Polymer makes it easier and faster to create anything from a button to a complete application across desktop, mobile, and beyond.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While I think being able to create custom elements and encapsulating style and behavior is fantastic, I&apos;m frustrated with the way it&apos;s being positioned. It sounds like you should use this for everything now. &lt;/p&gt;
&lt;p&gt;Here&apos;s the kicker: I don&apos;t know of any significant Google app that uses polymer for anything.&lt;/p&gt;
&lt;p&gt;That&apos;s a red flag for me. Please don&apos;t misunderstand, &lt;em&gt;obviously&lt;/em&gt; this is all new stuff and change takes time. My issue is just that the messaging on the site and from the Google engineers working on this don&apos;t convey that new-ness.&lt;/p&gt;
&lt;p&gt;In addition, even if you were to create custom elements for all the view code in your single page app, something has to manage the creation/destruction of those elements. You still have to manage state and orchestrate an app, which means your custom elements are really just another way to write the equivalent of a Backbone view. In the single page app world, I don&apos;t see what we would actually gain by switching those things to custom elements.&lt;/p&gt;
&lt;h3 id=&quot;pros-3&quot;&gt;&lt;a href=&quot;#pros-3&quot; aria-label=&quot;pros 3 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;pros&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Being able to create things like custom form inputs without them being baked into the browser is awesome.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Polymer polyfills enough so you can start using and experimenting with this functionality now.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Proper isolation of styles when building widgets has been a problem on the web for &lt;em&gt;years&lt;/em&gt;. The new standards solve that problem at the browser level, which is awesome.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;cons-3&quot;&gt;&lt;a href=&quot;#cons-3&quot; aria-label=&quot;cons 3 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;cons&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I personally feel like one of Google&apos;s main motivations for doing this is to make it dead simple to drop in Google services that include behavior, style and functionality into a web page without having to know &lt;em&gt;any&lt;/em&gt; JS. I could be completely off base here, but I can&apos;t help but feel like the marketing push is largely a big hype push to help push the standards through.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HTML Imports seem like a bad idea to me. It&apos;s feels like the CSS @import problem all over again. If you import a thing, you have to wait to get it back before the browser notices that it imports another thing, etc. So if you actually take this fully componentized approach to building a page that is promoted, then you&apos;ll end up with a ton of back and forth network requests. They do have a tool called the &quot;vulcanizer&quot; for flattening these things out, however. But inlining it doesn&apos;t seem to be an option. There&apos;s was a whole post written yesterday about &lt;a href=&quot;http://tjvantoll.com/2014/08/12/the-problem-with-using-html-imports-for-dependency-management/&quot;&gt;the problems with HTML imports&lt;/a&gt; that discusses this and other issues.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I simply don&apos;t understand why Google is pushing this stuff so hard as if it&apos;s some kind of panacea when the only example I can find of Google using it themselves is on the Polymer site itself. The site claims &quot;Polymer makes it easier and faster to create anything from a button to a complete application across desktop, mobile, and beyond.&quot; In my experimentation, that simply wasn&apos;t the case, I smell hype.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;my-fallible-conclusion-3&quot;&gt;&lt;a href=&quot;#my-fallible-conclusion-3&quot; aria-label=&quot;my fallible conclusion 3 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;my fallible conclusion&lt;/h3&gt;
&lt;p&gt;Google doesn&apos;t seem to be eating their own dog food here. The &lt;code class=&quot;language-text&quot;&gt;document.registerElement&lt;/code&gt; spec is exciting, beyond poly-filling that, I see no use for Polymer, sorry.&lt;/p&gt;
&lt;h2 id=&quot;backbone&quot;&gt;&lt;a href=&quot;#backbone&quot; aria-label=&quot;backbone permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Backbone&lt;/h2&gt;
&lt;p&gt;There is no more broadly production deployed single page app framework than Backbone that I&apos;m aware of. The &lt;a href=&quot;http://backbonejs.org/#examples&quot;&gt;examples section of the backbone docs&lt;/a&gt; lists a lot of big names and that list is far from exhaustive.&lt;/p&gt;
&lt;h3 id=&quot;pros-4&quot;&gt;&lt;a href=&quot;#pros-4&quot; aria-label=&quot;pros 4 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;pros&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It&apos;s a small and flexible set of well-tested building blocks.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Models&lt;/li&gt;
&lt;li&gt;Collections&lt;/li&gt;
&lt;li&gt;Views&lt;/li&gt;
&lt;li&gt;Router&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It solves a lot of the basic problems. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Its limited scope makes it easy to understand. As a result I always make new front end developer read the Backbone.js documentation as a first task when they join &amp;#x26;yet.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;cons-4&quot;&gt;&lt;a href=&quot;#cons-4&quot; aria-label=&quot;cons 4 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;cons&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It doesn&apos;t provide solutions for all the problems you&apos;ll encounter. This is why &lt;em&gt;every&lt;/em&gt; major user of backbone that I&apos;m aware of has built their own &quot;framework&quot; on top of Backbone&apos;s base. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Most notably find yourself missing when using plain Backbone are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A way to create derived properties on models. &lt;/li&gt;
&lt;li&gt;A way to bind properties and derived properties to views.&lt;/li&gt;
&lt;li&gt;A way to render a collection of views within an element.&lt;/li&gt;
&lt;li&gt;A way to cleanly handle &quot;subviews&quot; and nested layouts, etc. &lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As much as backbone is minimalistic, it&apos;s pieces also arguably too coupled to each other. For example, until &lt;a href=&quot;https://github.com/jashkenas/backbone/pull/3052&quot;&gt;my merged pull request is released&lt;/a&gt; you couldn&apos;t use any other type of Model within a Backbone Collection without monkey patching internal methods. This may not matter for some apps, but it does matter if I want to, for example, use a model to store some observable data in a library intended for use by other code that may or not be a backbone app. The only way to use Backbone Models is to include all of Backbone which feels odd and inefficient to me. &lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;my-fallible-conclusion-4&quot;&gt;&lt;a href=&quot;#my-fallible-conclusion-4&quot; aria-label=&quot;my fallible conclusion 4 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;my fallible conclusion&lt;/h3&gt;
&lt;p&gt;Backbone pioneered a lot of amazing things. I&apos;ve been using it since 0.3 and I strongly agree with its minimalistic philosophy. &lt;/p&gt;
&lt;p&gt;It&apos;s helped spawn a new generation of applications that treat the browser as a runtime, not just a document rendering engine.  But, its narrow scope left people to invent solutions on top of Backbone. While this isn&apos;t a bad thing, per sé, it just brings to light that there are more problems to be solved. &lt;/p&gt;
&lt;h2 id=&quot;not-using-a-framework&quot;&gt;&lt;a href=&quot;#not-using-a-framework&quot; aria-label=&quot;not using a framework permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Not using a framework&lt;/h2&gt;
&lt;p&gt;There&apos;s a subset of developers who think you shouldn&apos;t use frameworks, for anything ever. While I appreciate the sentiment and find myself very in line with many of them generally, to me it&apos;s simply not pragmatic, especially in a team scenario. &lt;/p&gt;
&lt;p&gt;I tend to agree with &lt;a href=&quot;http://blog.ryanflorence.com/you-cant-not-have-a-framework.html&quot;&gt;Ryan Florence&apos;s Post&lt;/a&gt; on this topic. Which is best summed up by this one quote from his post:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When you decide to not pick a public framework, you will end up with a framework anyway: your own.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He goes on to say, that doing this is not inherently bad, just that you should be serious about it and maintain it, etc.  I highly recommend the post, it&apos;s excellent.&lt;/p&gt;
&lt;h3 id=&quot;pros-5&quot;&gt;&lt;a href=&quot;#pros-5&quot; aria-label=&quot;pros 5 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;pros&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Ultimate flexibility&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&apos;ll tend to include &lt;em&gt;only&lt;/em&gt; the exact code that you need in your app. &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons-5&quot;&gt;&lt;a href=&quot;#cons-5&quot; aria-label=&quot;cons 5 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;cons&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Massive re-inventing of things, cost.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Knowing what modules to use and finding the right modules is hard&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;No clear documentation or conventions for new developers&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Really hard to transfer and re-use code for your next project&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&apos;ll generally end up having learn from your own mistakes instead of benefiting from other&apos;s code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-giant-gap&quot;&gt;&lt;a href=&quot;#the-giant-gap&quot; aria-label=&quot;the giant gap permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The GIANT gap&lt;/h2&gt;
&lt;p&gt;In doing &lt;a href=&quot;http://andyet.com/training/human-javascript-live&quot;&gt;our trainings&lt;/a&gt; and in writing &lt;a href=&quot;http://humanjavascript.com/&quot;&gt;my book, Human JavaScript&lt;/a&gt; and within our team itself we&apos;ve come to realize there is a huge gap between picking a tool, framework, or library and &lt;em&gt;actually building a complete application&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;Not to mention, there are huge problems surrounding how to actually build an app as a team without stomping on each other. &lt;/p&gt;
&lt;p&gt;There are sooooo many options and patterns on how to structure, build, and deploy applications beyond just picking a framework. &lt;/p&gt;
&lt;p&gt;Few people seem to be talking about how to do all of that, which is just as big of a rabbit hole as picking a framework!&lt;/p&gt;
&lt;h2 id=&quot;what-we-actually-want&quot;&gt;&lt;a href=&quot;#what-we-actually-want&quot; aria-label=&quot;what we actually want permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What we actually want&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Clear starting point&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A clear, but not enforced, standard way to do things&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Explicitly clear separation of concerns, so we can mix and match and replace as needed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Easy dependency management&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A way to use existing solutions so we don&apos;t have to re-invent everything&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A development workflow where we can switch from development mode to production with a simple boolean in a config.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-weve-addressed-all-of-these-things&quot;&gt;&lt;a href=&quot;#how-weve-addressed-all-of-these-things&quot; aria-label=&quot;how weve addressed all of these things permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How we&apos;ve addressed all of these things&lt;/h2&gt;
&lt;p&gt;So, in case you hadn&apos;t already heard, we did the unspeakable thing in JavaScript. We made a &quot;new&quot; framework: &lt;a href=&quot;http://ampersandjs.com&quot;&gt;Ampersand.js&lt;/a&gt; It&apos;s a bit like a redux or derivation of Backbone. &lt;/p&gt;
&lt;p&gt;The response so far, has been overwhelmingly positive, we only announced it about a month ago and &lt;a href=&quot;http://ampersandjs.com/contribute&quot;&gt;all these folks&lt;/a&gt; have jumped in to contribute. People have been giving talks about it &lt;a href=&quot;https://www.youtube.com/watch?v=UzJCz1qAiHg&quot;&gt;at meetups&lt;/a&gt;, and &lt;a href=&quot;https://twitter.com/jashkenas&quot;&gt;Jeremy Ashkenas&lt;/a&gt;, the creator of Backbone.js, Underscore.js, and CoffeeScript invited me to give a keynote at &lt;a href=&quot;http://backboneconf.com/&quot;&gt;BackboneConf 2014&lt;/a&gt; about Ampersand.js.&lt;/p&gt;
&lt;p&gt;So how did we address all my critiques about the other tools?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Flexible but cohesive&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It comes with a set of &quot;core&quot; modules (&lt;a href=&quot;http://ampersandjs.com/docs&quot;&gt;documented here&lt;/a&gt;) that roughly line up with the components in Backbone. But they are all installed and used individually. No assumptions are made that you&apos;re using a RESTful or even Ajax powered API. If you don&apos;t want that stuff, you just use Ampersand-State instead of the decorated version of State we call Ampersand-Model that adds the restful methods.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It doesn&apos;t come with a templating language. Templates can be as simple as a string of HTML, a function that return a string of HTML, or a function that return DOM. The sample app includes some more advanced templating with templatizer, but it truly could be anything. One awesome approach for doing handlebars/htmlbars + Ember style in-template binding declarations is &lt;a href=&quot;https://github.com/latentflip/domthing&quot;&gt;domthing&lt;/a&gt; by &lt;a href=&quot;http://twitter.com/philip_roberts&quot;&gt;Philip Roberts&lt;/a&gt;. There are also people using React with Ampersand views.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Views have a way to declare bindings separate from the template engine. So if you want, you can use HTML strings for templates and still get full control of bindings. The nice thing about not bundling a templating engine means that you can write componentized/reusable views without needing to also include a templating system.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There has to be a clear starting point and some idiomatic way to structure the app as a whole that can be used as a reference, but those standard approaches should not enforced. We did this by building a CLI that can help you spin up a new app, that follows all these conventions that can serve either as a starting point, or simply as a reference. See the &lt;a href=&quot;http://ampersandjs.com/learn/quick-start-guide&quot;&gt;quick start guide&lt;/a&gt; for more. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We wanted to build on something proven not just start something new for the sake of doing it. This is why we built on Backbone as a base instead of starting from scratch entirely.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We wanted a more complete reference guide to fill that gap I mentioned that explains all the surrounding ideas, tools, and philosophies. We did this by writing a book on the topic: Human JavaScript. It&apos;s &lt;a href=&quot;http://read.humanjavascript.com/&quot;&gt;free to read online in its entirety&lt;/a&gt; and available as an &lt;a href=&quot;https://gum.co/humanjs?wanted=true&quot;&gt;ebook&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We wanted to make it easy to use &quot;solved problems&quot; so we don&apos;t have to re-invent the wheel all the time. We did this by using npm for all package management, and by creating a &lt;a href=&quot;http://tools.ampersandjs.com/&quot;&gt;quick-searchable directory of our favorite clientside modules&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We wanted a painless development-to-production workflow. We did this with a tool called &lt;a href=&quot;https://github.com/HenrikJoreteg/moonboots&quot;&gt;moonboots&lt;/a&gt; that adds some dev and deployment workflow functionality to browserify. Moonboots has a plugin for &lt;a href=&quot;http://hapijs.com/&quot;&gt;hapi.js&lt;/a&gt; and &lt;a href=&quot;http://expressjs.com/&quot;&gt;express.js&lt;/a&gt; where the only thing you have to do to go from production mode (minified, cached, uniquely named static assets) and dev mode (re-built on each request, not minified, not cached) is toggling a single boolean.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We didn&apos;t just want this to be an &amp;#x26;yet project, it has to be bigger than that. We&apos;ve already had over 40 contributors in the short time Ampersand.js has been public, and we just added the first of hopefully many non-&amp;#x26;yet contributors to core. Everything uses the very permissivie MIT license and its modular, loosely coupled structure lends itself quite well to extending or replacing any piece of it to fit your needs. For clarity we&apos;ve also set it up as &lt;a href=&quot;http://github.com/AmpersandJS&quot;&gt;its own organization&lt;/a&gt; on GitHub. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We wanted additional training and support to be available if needed. For this we&apos;ve made the #&amp;#x26;yet IRC channel on freenode open to questions and support. In addition there are people and companies who want paid training opportunities to be available in order for them to even feel comortable adopting a technology. They want to know that more information and help is available, so in addition to the free resources, we&apos;ve also put together a &lt;a href=&quot;http://learn.humanjavascript.com/&quot;&gt;Human JavaScript code-along online training&lt;/a&gt; and offer &lt;a href=&quot;http://live.humanjavascript.com&quot;&gt;in person training events&lt;/a&gt; to provide hands-on training and support.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;so-are-you-saying-ampersand-is-the-best-choice-for-everyone&quot;&gt;&lt;a href=&quot;#so-are-you-saying-ampersand-is-the-best-choice-for-everyone&quot; aria-label=&quot;so are you saying ampersand is the best choice for everyone permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So are you saying Ampersand is the best choice for everyone?&lt;/h2&gt;
&lt;p&gt;Nope. Not at all. It certainly has its own set of tradeoffs. Here are some I&apos;m aware of, there are probably others:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Unsurprisingly, it is still a somewhat immature codebase compared to some of these other tools. Having said that, however, we use it for all our single page app projects at &lt;a href=&quot;https://andyet.com&quot;&gt;&amp;#x26;yet&lt;/a&gt; and the core modules all have thorough test suites. It&apos;s also worth noting that if you &lt;em&gt;do&lt;/em&gt; run into a problem, odds are it won&apos;t be as debilitating. Its open, hackable, pluggable nature makes it different than many frameworks in that you don&apos;t have to jump through a bunch of hoops to fix or overwrite something in your app. The small modules typically make it easier to isolate, patch, and quickly publish bugfixes. In fact, we often publish a patched version to npm as soon as a pull request is merged. Our strict adherance to &lt;a href=&quot;http://semver.org/&quot;&gt;semver&lt;/a&gt; makes it possible to do that while mitigating odds of breaking any existing code. I think that&apos;s part of the reason it has gotten as many pull requests as it has already. Even still, if you have a different idea of how something should work, it&apos;s easy to use your own module instead. We&apos;re also trying to increase the number of core committers to make sure the patches are getting in even if other core devs are busy. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It doesn&apos;t have the rich tooling and giant communities built up around it yet. That stuff takes time, but as I said, we&apos;re encouraged by the level of participation we&apos;ve had thus far. Please file bugs and help create the things you wish existed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Old browser support is a rough spot. We intentionally drew a line saying we won&apos;t support IE8. We&apos;re not the alone there, &lt;a href=&quot;http://jquery.com/browser-support/&quot;&gt;jQuery 2.0 doesn&apos;t either&lt;/a&gt;, Google has said they&apos;ll only support the latest two versions of IE for Apps and &lt;a href=&quot;http://googlesystem.blogspot.com/2013/11/google-drops-support-for-ie9.html&quot;&gt;recently dropped IE9 too&lt;/a&gt;,  and Microsoft themselves &lt;a href=&quot;http://blogs.msdn.com/b/ie/archive/2014/08/07/stay-up-to-date-with-internet-explorer.aspx&quot;&gt;just announced their plan to phase out support for all older browsers&lt;/a&gt;. Why did we do this? It&apos;s because we&apos;re using [getters and setters] for the state management stuff. It was a hard decision but felt like enough of a win to make it worth it. Unfortunately, since that is a language-level feature, It&apos;s not easily shimmable (at least not that I&apos;m aware of). Sadly, for some companies not supporting IE8 is a dealbreaker. Perhaps someone has already written a transpiler in a browserify transform that can solve this problem, but I&apos;m not aware of that. If you are, please let me know. I would love it if Ampersand-State could support IE 7 and 8.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;&lt;a href=&quot;#final-thoughts&quot; aria-label=&quot;final thoughts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;Hopefully this explanation was useful. If you have any feedback, thoughts or if there&apos;s something I missed or got wrong I&apos;m &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; on twitter, please let me know.&lt;/p&gt;
&lt;p&gt;Also please help us make these tools better. We love getting more people involved in the project. File bugs or grab one of the &lt;a href=&quot;http://issues.ampersandjs.com&quot;&gt;open issues&lt;/a&gt; and help us patch &apos;em.&lt;/p&gt;
&lt;h1 id=&quot;want-to-start-using-ampersand&quot;&gt;&lt;a href=&quot;#want-to-start-using-ampersand&quot; aria-label=&quot;want to start using ampersand permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Want to start using Ampersand?&lt;/h1&gt;
&lt;p&gt;Check the &lt;a href=&quot;http://ampersandjs.com/learn&quot;&gt;learning guides&lt;/a&gt;, &lt;a href=&quot;http://ampersandjs.com/docs&quot;&gt;API reference&lt;/a&gt;, or &lt;a href=&quot;http://read.humanjavascript.com/&quot;&gt;read Human JavaScript online for free&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For hands-on learning jump into the &lt;a href=&quot;http://learn.humanjavascript.com/&quot;&gt;Human JavaScript code-along online training&lt;/a&gt;, or for the ultimate kickstart &lt;a href=&quot;http://live.humanjavascript.com&quot;&gt;come hang out in person at our training events&lt;/a&gt; where you&apos;ll build an app from scratch together with us.&lt;/p&gt;
&lt;p&gt;See you on the Interwebz &amp;#x3C;3&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Human JavaScript scholarship]]></title><description><![CDATA[In an effort to build a more inclusive community around the events we're a part of, we'd like to announce our very first (but certainly not…]]></description><link>https://blog.andyet.com/2014/08/06/apply-for-the-human-javascript-scholarship/</link><guid isPermaLink="false">https://blog.andyet.com/2014/08/06/apply-for-the-human-javascript-scholarship/</guid><pubDate>Wed, 06 Aug 2014 13:34:35 GMT</pubDate><content:encoded>&lt;p&gt;In an effort to build a more inclusive community around the events we&apos;re a part of, we&apos;d like to announce our very first (but certainly not last) &lt;strong&gt;Human JavaScript Training Scholarship&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We understand that very few people, both in tech and in the world, have access to the resources needed to level-up in their careers. This is especially true of marginalized groups, who are consistently underrepresented and often even pushed out of our industry without the opportunity to thrive here. &lt;/p&gt;
&lt;p&gt;We also understand that there are serious barriers to entry in our industry that keep people who are marginalized by race and/or gender from entering and actively participating in our field.  &lt;/p&gt;
&lt;p&gt;With this in mind, we&apos;ll be covering one person&apos;s trip and tuition to participate in &lt;a href=&quot;http://andyet.com/training/human-javascript-live&quot;&gt;Human JavaScript: LIVE!&lt;/a&gt;, our two-day, intensive JavaScript workshop for JS developers who are looking to level-up in building clientside, single-page web apps. This workshop focuses on writing modular and maintainable code, while emphasizing the importance of code collaboration.&lt;/p&gt;
&lt;h2 id=&quot;whats-included&quot;&gt;&lt;a href=&quot;#whats-included&quot; aria-label=&quot;whats included permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What&apos;s included?&lt;/h2&gt;
&lt;p&gt;We&apos;ll cover your round-trip flight to Washington state and your tuition to our &lt;a href=&quot;http://andyet.com/training/human-javascript-live&quot;&gt;Human JavaScript: LIVE!&lt;/a&gt; training workshop, August 26-27. All attendee transportation, meals, and hotel stays are 100% covered by the cost of tuition and will be handled by our event team here in Richland. As a part of the scholarship, you&apos;ll also receive access to all of our Human JavaScript training videos online (forever) and &lt;a href=&quot;http://humanjavascript.com/&quot;&gt;the Human JavaScript book&lt;/a&gt; (also forever). We also thought it&apos;d be rad to send you some of our favorite &amp;#x26;yet goodies, hand-crafted by our design team.&lt;/p&gt;
&lt;h2 id=&quot;ok-so-how-do-i-apply&quot;&gt;&lt;a href=&quot;#ok-so-how-do-i-apply&quot; aria-label=&quot;ok so how do i apply permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&quot;Ok, so how do I apply?&quot;&lt;/h2&gt;
&lt;p&gt;We want to hear your Developer Origin Story™. How&apos;d you get started in tech? What do you wish you had known when you got started? We want to know what you love about being a developer and what, as a community, we can do to lower the barriers to entry marginalized groups often face.&lt;/p&gt;
&lt;p&gt;You can submit your story privately to us &lt;a href=&quot;http://andyet.com/training/human-javascript-scholarship&quot;&gt;here&lt;/a&gt;, or you can publish it as a blog post, webpage, or video and link us to it &lt;a href=&quot;http://andyet.com/training/human-javascript-scholarship&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You &lt;em&gt;want&lt;/em&gt; to be a great JavaScript developer.&lt;/li&gt;
&lt;li&gt;You are a person of color and/or you identify significantly as a woman.&lt;/li&gt;
&lt;li&gt;You agree to honor our &lt;a href=&quot;http://andyet.com/code-of-conduct&quot;&gt;Code of Conduct&lt;/a&gt;, because people come first at our events.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;All of &amp;#x26;yet&apos;s events and workshops are trans-inclusive.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Human JavaScript: LIVE!&apos;s venue is completely ADA accessible and we are happy to provide ASL resources for anyone who needs them. Please let us know what we can do to help make you feel at home.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://andyet.com/training/human-javascript-scholarship&quot;&gt;Apply now for the Human JavaScript Scholarship&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deadline to apply is next Wednesday, August 13th, 2014&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;need-some-help-getting-started-with-your-origin-story&quot;&gt;&lt;a href=&quot;#need-some-help-getting-started-with-your-origin-story&quot; aria-label=&quot;need some help getting started with your origin story permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Need some help getting started with your origin story?&lt;/h2&gt;
&lt;p&gt;One of our favorite hashtags this year was &lt;a href=&quot;https://twitter.com/search?q=%23mynerdstory&amp;#x26;src=tyah&quot;&gt;#mynerdstory&lt;/a&gt;, started by &lt;a href=&quot;https://twitter.com/skinny&quot;&gt;Crystal Beasley&lt;/a&gt; to encourage women and other marginalized groups in tech to share how they got started in the tech industry. &lt;/p&gt;
&lt;p&gt;Here&apos;s a few example origin stories from #mynerdstory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://skinnywhitegirl.com/blog/my-nerd-story/1101/&quot;&gt;Here&apos;s Crystal&apos;s story&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://kronda.com/my-nerd-story&quot;&gt;Frontend Dev Kronda Adair&apos;s &lt;em&gt;My Nerd Story&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ednapiranha.com/2014/the-tech-story-of-edna/&quot;&gt;JS Dev Jen Fong&apos;s &lt;em&gt;The Tech Story of Edna&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition to applying for the scholarship to participate in &lt;a href=&quot;http://andyet.com/training/human-javascript-live&quot;&gt;Human JavaScript: LIVE!&lt;/a&gt;, when you apply you&apos;ll receive a $300 discount to attend the workshop, just to say thank you for being awesome.&lt;/p&gt;
&lt;p&gt;We want to thank our community for continuing to inspire and guide us toward making our events more inclusive. We appreciate you all so much. &lt;/p&gt;
&lt;p&gt;❤&lt;/p&gt;
&lt;p&gt;If you&apos;re looking to help us spread the word please use the hashtag &lt;a href=&quot;https://twitter.com/search?f=realtime&amp;#x26;q=%23HJSLScholarship&amp;#x26;src=typd&quot;&gt;#HJSLScholarship&lt;/a&gt; or tweet us → &lt;a href=&quot;https://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Talky for iOS is now available on the App Store]]></title><description><![CDATA[We are very excited to announce that the iOS app for Talky is now available for download on the App Store.(Can I get a woohoo?)Take a quick…]]></description><link>https://blog.andyet.com/2014/06/26/talky-for-ios-now-available-on-the-app-store/</link><guid isPermaLink="false">https://blog.andyet.com/2014/06/26/talky-for-ios-now-available-on-the-app-store/</guid><pubDate>Thu, 26 Jun 2014 13:34:35 GMT</pubDate><content:encoded>&lt;p&gt;We are very excited to announce that the iOS app for &lt;a href=&quot;http://talky.io&quot;&gt;Talky&lt;/a&gt; is now available for &lt;a href=&quot;https://itunes.apple.com/app/talky-free-video-conferencing/id882057960&quot;&gt;download on the App Store&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(Can I get a woohoo?)&lt;/p&gt;
&lt;h3 id=&quot;take-a-quick-look&quot;&gt;&lt;a href=&quot;#take-a-quick-look&quot; aria-label=&quot;take a quick look permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Take a quick look&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://a5.mzstatic.com/us/r30/Purple2/v4/f2/37/36/f2373637-066b-776c-2c57-1f05fcbb37c5/screen520x924.jpeg&quot; alt=&quot;join room screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;You&apos;ll use the same approach to starting a conversation as Talky on the web.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://a2.mzstatic.com/us/r30/Purple4/v4/d9/54/57/d95457c4-8b70-b3aa-c796-234809ac01d6/screen520x924.jpeg&quot; alt=&quot;joined room screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;One quick tap and you&apos;ll be able to copy the room&apos;s URL, or just click the &quot;+&quot; and send an invite via text or email.&lt;/p&gt;
&lt;p&gt;In addition to other iOS users, the people you invite can use Talky on Chrome, Firefox, or Opera on the desktop, or on Chrome or Firefox on Android devices.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://a2.mzstatic.com/us/r30/Purple/v4/f5/4c/07/f54c07a1-faa0-8c14-2230-1f66683f0d80/screen520x924.jpeg&quot; alt=&quot;three people on screen&quot;&gt;&lt;/p&gt;
&lt;p&gt;(Unfortunately, we regret to inform you that not &lt;em&gt;all&lt;/em&gt; Talky conversations will feature the most delightfully amazing &lt;a href=&quot;http://andyet.com/team/leslie&quot;&gt;Leslie&lt;/a&gt;!)&lt;/p&gt;
&lt;h3 id=&quot;the-rest-of-the-story&quot;&gt;&lt;a href=&quot;#the-rest-of-the-story&quot; aria-label=&quot;the rest of the story permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The rest of the story&lt;/h3&gt;
&lt;p&gt;Not long ago, in January 2014, the conversation around integrating iOS with WebRTC started to gain momentum here at &amp;#x26;yet.&lt;/p&gt;
&lt;p&gt;With the addition of &lt;a href=&quot;http://andyet.com/team/peter&quot;&gt;Peter Saint-Andre&lt;/a&gt;, formerly an architect on Cisco&apos;s WebEx service and an area director at the IETF, and WebRTC expert &lt;a href=&quot;http://andyet.com/team/fippo&quot;&gt;Philipp Hancke&lt;/a&gt; to our team, we were poised to take Talky development to the next level.&lt;/p&gt;
&lt;p&gt;When we first released Talky in 2013, it was already solving a big problem for our team. Talky gave us the ability to communicate more naturally and effectively, especially as a distributed team. It was originally a demo for &lt;a href=&quot;http://simplewebrtc.com&quot;&gt;SimpleWebRTC&lt;/a&gt;, a Javascript library you can use to quickly build apps like Talky. But we had no idea how well it would be received. Talky continues to steadily grow and we &lt;em&gt;love&lt;/em&gt; hearing from all our users.&lt;/p&gt;
&lt;p&gt;The initial prototype for Talky iOS was created by &amp;#x26;yet&apos;s quietly awesome iOS developer, &lt;a href=&quot;http://andyet.com/team/hjon&quot;&gt;Jon Hjelle&lt;/a&gt;. Who, if you know well, was quite displeased with the mention of his name in this blog post. (Hjon, please accept my most sincere apologies!)&lt;/p&gt;
&lt;p&gt;The final Talky iOS app was completed in partnership with &lt;a href=&quot;http://steamclock.com&quot;&gt;Steamclock Software&lt;/a&gt;. The dev team at Steamclock polished the prototype through some major changes to the WebRTC library, including the very important addition of resilient video support. The end result is a more featureful app and delightful user experience.&lt;/p&gt;
&lt;p&gt;The iOS app also paves the way for our forthcoming &lt;a href=&quot;http://talky.pro&quot;&gt;Talky Pro&lt;/a&gt; service, which will give users the same experience as Talky, but optimized for business, complete with personalized branding.&lt;/p&gt;
&lt;p&gt;Talky is built on top of the &lt;a href=&quot;http://otalk.org&quot;&gt;Otalk&lt;/a&gt; platform, a suite of completely open and standards-based tools for making modern communication a delightful experience for developers and users alike.&lt;/p&gt;
&lt;p&gt;As a team we&apos;re excited about WebRTC and its future contributions to open communication.&lt;/p&gt;
&lt;p&gt;If you have a WebRTC project you think we could help with, &lt;a href=&quot;mailto:projects+webrtc@andyet.com&quot;&gt;we&apos;d love to hear about it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just want to chat? We&apos;d &lt;a href=&quot;mailto:contact@andyet.com&quot;&gt;love to hear from you, too!&lt;/a&gt; =)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing Ampersand.js]]></title><description><![CDATA[Introducing Ampersand.js a highly modular, loosely coupled, non-frameworky framework for building advanced JavaScript apps.Why!?!We <…]]></description><link>https://blog.andyet.com/2014/06/25/introducing-ampersand-js/</link><guid isPermaLink="false">https://blog.andyet.com/2014/06/25/introducing-ampersand-js/</guid><pubDate>Wed, 25 Jun 2014 14:32:00 GMT</pubDate><content:encoded>&lt;p&gt;Introducing &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt; a highly modular, loosely coupled, non-frameworky framework for building advanced JavaScript apps.&lt;/p&gt;
&lt;h2 id=&quot;why&quot;&gt;&lt;a href=&quot;#why&quot; aria-label=&quot;why permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why!?!&lt;/h2&gt;
&lt;p&gt;We &amp;#x3C;3 &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt; at &lt;a href=&quot;http://andyet.com&quot;&gt;&amp;#x26;yet&lt;/a&gt;. It’s brilliantly simple code and it solves many common problems in developing clientside applications.&lt;/p&gt;
&lt;p&gt;But we missed the focused simplicity of tiny modules in node-land. We wanted something similar in style and philosophy, but that fully embraced tiny modules, npm, and browserify.&lt;/p&gt;
&lt;p&gt;So we made &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt;, a well-defined approach to combining (get it?) a series of intentionally tiny, and loosely coupled modules for building JS apps.&lt;/p&gt;
&lt;h3 id=&quot;post-backbone&quot;&gt;&lt;a href=&quot;#post-backbone&quot; aria-label=&quot;post backbone permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Post-Backbone&lt;/h3&gt;
&lt;p&gt;Backbone has been praised for its flexibility and simplicity. The fact that Backbone’s author &lt;a href=&quot;http://twitter.com/jashkenas&quot;&gt;Jeremy Ashkenas&lt;/a&gt; and his fellow maintainers haven’t tried to solve &lt;em&gt;every&lt;/em&gt; problem has kept it usable for a broad range of application types. Its effectiveness is evidenced by &lt;a href=&quot;http://backbonejs.org/#examples&quot;&gt;its incredible popularity&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/henrikjoreteg&quot;&gt;I&lt;/a&gt; built my first Backbone app when it was still version 0.3.1, and our whole team has been an avid users/supporters of the project for quite some time. I even got a chance to speak at the first BackboneConf.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/philip_roberts&quot;&gt;Philip Roberts&lt;/a&gt;, who has built a big portion of Ampersand.js, got a lot of experience building an incredibly complex Backbone app at his previous company &lt;a href=&quot;http://floatapp.com/&quot;&gt;Float&lt;/a&gt;. He certainly pushed Backbone to its limits in building complex spreadsheet-esque accounting tools for the web.&lt;/p&gt;
&lt;p&gt;Not long after discovering Backbone at &amp;#x26;yet, we got really into node.js, which brought with it a module approach and what became an awesome way of managing dependencies that we’ve have fallen deeply in like with: &lt;a href=&quot;https://npmjs.org&quot;&gt;npm&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nothing has done more for our team’s ability to write clean, maintainable clientside applications than having a really awesome dependency management system and &lt;a href=&quot;http://twitter.com/substack&quot;&gt;substack’s&lt;/a&gt; &lt;a href=&quot;http://browserify.org/&quot;&gt;browserify&lt;/a&gt; that allows us to quickly declare/install external dependencies and know that things will Just Work™.&lt;/p&gt;
&lt;p&gt;npm has also been the catalyst that enables what has been referred to as the &quot;tiny modules movement&quot;, the basic philosophy of which is that no matter how small or insignificant the problem, you shouldn’t have to solve it more than once. &lt;/p&gt;
&lt;p&gt;By giving a module narrow scope and functionality you can actually maintain it without burning out. Also, knowing about and fixing gotchas in a single location means that all modules depending on it also benefit.&lt;/p&gt;
&lt;p&gt;After getting addicted to this way of working, many developers, ourselves included, have developed an allergic reaction to libraries and plugins that &lt;em&gt;don’t&lt;/em&gt; work that way. Unfortunately, despite its lightweight, flexible approach, Backbone itself doesn’t follow that pattern.&lt;/p&gt;
&lt;p&gt;&quot;What? I thought you said Backbone was flexible and modular?&quot;&lt;/p&gt;
&lt;p&gt;Yes, but only to a point. &lt;/p&gt;
&lt;p&gt;&quot;But, Backbone &lt;em&gt;is&lt;/em&gt; on npm!&quot;&lt;/p&gt;
&lt;p&gt;Yes, but stay with me...&lt;/p&gt;
&lt;p&gt;One of the problems we’ve had at &lt;a href=&quot;http://andyet.com&quot;&gt;&amp;#x26;yet&lt;/a&gt; especially when working on large Backbone applications is a sane way to document the type of properties a model is supposed to contain.&lt;/p&gt;
&lt;p&gt;Backbone models, by default, don’t enforce any structure. You don’t have to declare anywhere what properties you’re going to store. As a result, people inevitably start saving miscellaneous properties on models from within a view somewhere, and there’s no good way for a new dev starting in on the project to be able to read the models and see exactly what state is being tracked.&lt;/p&gt;
&lt;p&gt;To solve this problem and to enforce additional structure, I wrote a replacement model called &quot;HumanModel&quot; that is consistent with the philosophy explored in depth in the book &lt;a href=&quot;http://humanjavascript.com&quot;&gt;Human JavaScript&lt;/a&gt;. This model, which has now morphed into &lt;a href=&quot;https://github.com/ampersandjs/ampersand-model&quot;&gt;ampersand-model&lt;/a&gt;, forces you to declare the properties you’re going to store, and also allows you to declare derived properties, etc.&lt;/p&gt;
&lt;p&gt;Originally we used our replacement models within Backbone Collections, but we started running into problems. Backbone generally assumes that you’re storing Backbone.Model models in collections. So when adding an instantiated model to a collection, Backbone would fail to realize that it’s already a model. &lt;a href=&quot;https://github.com/jashkenas/backbone/pull/3052&quot;&gt;My patch to Backbone&lt;/a&gt; was merged and fixed this, but there have been other areas where we’ve wanted more flexibility.&lt;/p&gt;
&lt;p&gt;For example, at times we wanted RESTful collections where data is coming from an API, but other times, we just wanted something &lt;em&gt;like&lt;/em&gt; a Backbone collection/model system for managing state in another module, that perhaps had nothing to do with getting data from a REST API. In those cases we didn’t want to make all of Backbone a dependency of our module, just to get evented models.&lt;/p&gt;
&lt;p&gt;Over time while building &lt;em&gt;a ton&lt;/em&gt; of apps with it, for clients and for ourselves, we’ve kept running into these same types of problems that we attributed to the coupling/bundling of Backbone.&lt;/p&gt;
&lt;p&gt;So we started ripping things apart into their own independently published, managed, and versioned modules. &lt;/p&gt;
&lt;p&gt;Thus, &lt;a href=&quot;http://ampersandjs.com/&quot;&gt;Ampersand.js&lt;/a&gt; was born.&lt;/p&gt;
&lt;p&gt;Ampersand.js splits things apart as much as possible. For example, &lt;a href=&quot;https://github.com/ampersandjs/ampersand-collection&quot;&gt;ampersand-collection&lt;/a&gt; makes no assumptions about how you’re going to put data into it, what types of objects you’re going to store, or what indices you’re going to want to use to retrieve them. It follows the tiny module pattern.&lt;/p&gt;
&lt;p&gt;But, what if you want that stuff? &lt;/p&gt;
&lt;p&gt;Well, that’s easy, we just have another tiny module that layers in that functionality. &lt;/p&gt;
&lt;p&gt;There’s a RESTful &lt;a href=&quot;https://github.com/ampersandjs/ampersand-rest-collection&quot;&gt;ampersand-rest-collection&lt;/a&gt; we just pre-bundle and publish it as a module for convenience, &lt;a href=&quot;https://github.com/AmpersandJS/ampersand-rest-collection/blob/master/ampersand-rest-collection.js&quot;&gt;the code that combines them&lt;/a&gt; is hilariously simple.&lt;/p&gt;
&lt;p&gt;You see the exact same pattern in &lt;a href=&quot;https://github.com/ampersandjs/ampersand-state&quot;&gt;ampersand-state&lt;/a&gt; and &lt;a href=&quot;https://github.com/ampersandjs/ampersand-model&quot;&gt;ampersand-model&lt;/a&gt;. &quot;State&quot; is the base object that &quot;model&quot; is built on. But model goes the additional step of including the RESTful methods.&lt;/p&gt;
&lt;h3 id=&quot;so-what-exactly-is-ampersandjs-what-makes-it-unique&quot;&gt;&lt;a href=&quot;#so-what-exactly-is-ampersandjs-what-makes-it-unique&quot; aria-label=&quot;so what exactly is ampersandjs what makes it unique permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So what exactly is Ampersand.js? What makes it unique?&lt;/h3&gt;
&lt;p&gt;In starting to toy with the concept of building out these tools, we wrote a few guiding principles, some of which we’ll no doubt get some flack for. Here they are:&lt;/p&gt;
&lt;h4 id=&quot;1-everything-is-a-commonjs-module&quot;&gt;&lt;a href=&quot;#1-everything-is-a-commonjs-module&quot; aria-label=&quot;1 everything is a commonjs module permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Everything is a CommonJS module&lt;/h4&gt;
&lt;p&gt;No AMD, UMD, or bundling of any kind is included by default. The clarity, simplicity, and flexibility of CommonJS just won. Clear dependencies, no unnecessary wrapping/indenting, no extra cruft. Just a clearly declared set of dependencies in package.json. &lt;/p&gt;
&lt;p&gt;Any sort of bundling for any other module system is easy enough to do with any number of tools like grunt or gulp.&lt;/p&gt;
&lt;h4 id=&quot;2-everything-is-installed-via-npm&quot;&gt;&lt;a href=&quot;#2-everything-is-installed-via-npm&quot; aria-label=&quot;2 everything is installed via npm permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. Everything is installed via npm&lt;/h4&gt;
&lt;p&gt;This isn’t a diss toward the other package management approaches, it’s just a choice to maximize simplicity. Especially given point #1.&lt;/p&gt;
&lt;h4 id=&quot;3-modern-browsers-by-default&quot;&gt;&lt;a href=&quot;#3-modern-browsers-by-default&quot; aria-label=&quot;3 modern browsers by default permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. Modern browsers by default&lt;/h4&gt;
&lt;p&gt;We’re unapologetically supporting only IE9+. There are many features of ES5 that enable dramatic simplifications of code that simply were not present in IE before IE9. For reference, check out &lt;a href=&quot;http://kangax.github.io/es5-compat-table/&quot;&gt;kangax’s ES5 compatibility table&lt;/a&gt;. Not having to shim each and every feature and completely avoiding non-shimmable ones saves you so many headaches that we decided to just draw that line. Bring the haters :) &lt;/p&gt;
&lt;p&gt;But again, remember this isn’t an all-or-nothing &quot;framework&quot;. In fact, very arguably it’s not a framework at all. There are pieces here that don’t require IE9 and others that could be converted to solve those problems if they matter to you. It’s just a line we chose to draw in the sand so we could focus our efforts on building for the web’s present and future instead of its past.&lt;/p&gt;
&lt;h4 id=&quot;4-strict-semver-all-the-things&quot;&gt;&lt;a href=&quot;#4-strict-semver-all-the-things&quot; aria-label=&quot;4 strict semver all the things permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;4. Strict semver all the things&lt;/h4&gt;
&lt;p&gt;If you’re unfamiliar with semver, &lt;a href=&quot;http://semver.org/&quot;&gt;the semver homepage&lt;/a&gt; summarizes it in about three sentences. In short, it’s a strict adherence to a versioning scheme for modules that, if followed, allows you to trust minor and patch version updates to &lt;em&gt;not break your code&lt;/em&gt;. So, for a dependency you can specify a version like this: &quot;^1.1.0&quot; and know that your code will not break if the underlying dependency is upgraded from 1.1.0 to 1.2.8 because the versioning scheme prohibits breaking changes without bumping the major version number. &lt;/p&gt;
&lt;p&gt;This flexibility is very important in clientside code because we don’t want to send 5 different versions of the same dependency to the browser. Loosely declaring dependencies of the building blocks and strictly declaring them in your app’s main package.json can help you avoid a lot of these problems. Combining the way npm manages dependencies with this approach, we can get minimal duplication of shared dependencies.&lt;/p&gt;
&lt;h4 id=&quot;5-tiny-module-all-the-things&quot;&gt;&lt;a href=&quot;#5-tiny-module-all-the-things&quot; aria-label=&quot;5 tiny module all the things permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;5. Tiny module all the things!&lt;/h4&gt;
&lt;p&gt;The smaller the feature set of the low-level modules, the easier it is to avoid breaking changes. Higher-level modules should still exist, but, should primarily be pulling together small modules in a way that makes them more usable. For example: &lt;a href=&quot;https://github.com/ampersandjs/ampersand-rest-collection&quot;&gt;ampersand-rest-collection&lt;/a&gt;, &lt;a href=&quot;https://github.com/component/events&quot;&gt;component’s &quot;events&quot; module&lt;/a&gt;, or &lt;a href=&quot;https://github.com/component/classes&quot;&gt;component’s &quot;classes&quot; module&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;6-expose-the-simplest-api-possible&quot;&gt;&lt;a href=&quot;#6-expose-the-simplest-api-possible&quot; aria-label=&quot;6 expose the simplest api possible permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;6. Expose the simplest API possible.&lt;/h4&gt;
&lt;p&gt;Simplicity is a core value. If you don’t actively fight for simplicity in software, complexity will win, and it will suck. This means things like pruning unneeded features and giving everything descriptive names even if they’re longer. That’s what minification is for. We are not compilers, so we should optimize for readability and use tools for optimizations.&lt;/p&gt;
&lt;p&gt;While this is going to be a bit controversial, for us the focus on simplicity also means avoiding using promises. There are enough things that are new and intimidating to those building clientside apps. Adding promises makes for an unnecessarily tall cognitive leap. &lt;/p&gt;
&lt;p&gt;Not that promises are bad, but the truth is there isn’t as much need for complex flow-control for most clientside things.&lt;/p&gt;
&lt;p&gt;And, if you want to use promises it’d be easy enough to write a version of &lt;a href=&quot;https://github.com/AmpersandJS/ampersand-sync&quot;&gt;ampersand-sync&lt;/a&gt; or &lt;a href=&quot;http://ampersandjs.com/docs/#ampersand-router&quot;&gt;ampersand-router&lt;/a&gt; that used &lt;a href=&quot;https://www.npmjs.org/package/bluebird&quot;&gt;bluebird&lt;/a&gt; or another promise library and slip that into your app. &lt;/p&gt;
&lt;p&gt;That’s the whole point of the modularity concept and still: you only include what you ultimately are using!&lt;/p&gt;
&lt;h4 id=&quot;7-optimize-for-minimal-dom-manipulation-and-performance&quot;&gt;&lt;a href=&quot;#7-optimize-for-minimal-dom-manipulation-and-performance&quot; aria-label=&quot;7 optimize for minimal dom manipulation and performance permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;7. Optimize for minimal DOM manipulation and performance.&lt;/h4&gt;
&lt;p&gt;It should be easy to create rich user experiences. &lt;/p&gt;
&lt;p&gt;There’s a lot of buzz and talk around rendering performance for JS apps. Mostly the answer to these types of performance issues is: &quot;Don’t touch the DOM any more than you have to.&quot;&lt;/p&gt;
&lt;p&gt;That’s one of the core premises of libraries like Facebook’s React: only performing minimal changes and batching those changes into RAF loops. &lt;/p&gt;
&lt;p&gt;**note: You could very easily use React with Ampersand.js, btw.&lt;/p&gt;
&lt;p&gt;In canonical Backbone apps you often re-render the contents of a view if the related model or models change. But, if you’re trying to do things like smooth dragging and dropping, you don’t want to re-render contents of a view each time properties change. Or even if you’re using CSS3 transitions, re-rendering a section of the DOM and adding a class won’t ever trigger the CSS3 transition, because it wasn’t actually transitioned, it was just replaced with another piece of DOM that had that class. So, pretty soon in those scenarios you find yourself writing a bunch of &quot;glue code&quot; to bind things to the DOM and only perform minimal edits. &lt;/p&gt;
&lt;p&gt;The point is, there are valid uses of both approaches. So the goal with &lt;a href=&quot;http://ampersandjs.com/docs/#ampersand-view&quot;&gt;ampersand-view&lt;/a&gt; is a simple way to declare your bindings in your view code. Check out the &lt;a href=&quot;http://ampersandjs.com/docs/#ampersand-view-bindings&quot;&gt;declarative bindings section&lt;/a&gt; of the docs. &lt;/p&gt;
&lt;p&gt;You can also just mix and match. In certain cases it may be easier to re-render everything, but declaring very specific binding behavior is also simple without tying you to a template system. It gives you ultimate control. Modularity FTW!&lt;/p&gt;
&lt;h4 id=&quot;8-mobile-is-in-the-dna&quot;&gt;&lt;a href=&quot;#8-mobile-is-in-the-dna&quot; aria-label=&quot;8 mobile is in the dna permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;8. Mobile is in the DNA&lt;/h4&gt;
&lt;p&gt;Think small and light. Optimize and build tools for touch interfaces.  Help build the web as the go-to platform for mobile. (You can expect more tools to be released here in the future toward this end.)&lt;/p&gt;
&lt;h4 id=&quot;9-unapologetically-designed-for-rich-app-experiences&quot;&gt;&lt;a href=&quot;#9-unapologetically-designed-for-rich-app-experiences&quot; aria-label=&quot;9 unapologetically designed for rich app experiences permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;9. Unapologetically designed for rich &quot;app&quot; experiences.&lt;/h4&gt;
&lt;p&gt;These ain’t no websites, pal. If you’re building content sites or sites you want thoroughly crawled this is not the tool for you. &lt;/p&gt;
&lt;p&gt;This is for clientside JavaScript applications where the browser is treated as a runtime, not as a document viewer. For more on that, you can read about how we believe &lt;a href=&quot;https://blog.andyet.com/2014/01/17/web-has-outgrown-the-browser&quot;&gt;the web has outgrown the browser&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;10-embrace-offline-first-mentality-and-serviceworker-all-the-things-as-soon-as-we-can&quot;&gt;&lt;a href=&quot;#10-embrace-offline-first-mentality-and-serviceworker-all-the-things-as-soon-as-we-can&quot; aria-label=&quot;10 embrace offline first mentality and serviceworker all the things as soon as we can permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;10. Embrace offline-first mentality and ServiceWorker all the things as soon as we can.&lt;/h4&gt;
&lt;p&gt;Yup. These are apps, they should compete with native apps. The thing that’s missing for web to &lt;em&gt;truly&lt;/em&gt; be a viable alternative to native apps is good tools for building offline web apps. Again, for more on that &lt;a href=&quot;https://blog.andyet.com/2014/01/17/web-has-outgrown-the-browser&quot;&gt;read the post mentioned above&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But the point is, in order for an app to work offline it needs to be a true self-contained JavaScript app so that it can run entirely in the client. Since that’s how Ampersand.js is aimed to work, it would be a nice compliment to an offline-first backend like &lt;a href=&quot;http://hood.ie/&quot;&gt;hood.ie&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;11-everything-is-mit-licensed&quot;&gt;&lt;a href=&quot;#11-everything-is-mit-licensed&quot; aria-label=&quot;11 everything is mit licensed permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;11. Everything is MIT licensed&lt;/h4&gt;
&lt;p&gt;Software licensing can suck. Especially when trying to manage licenses of dependencies for a large enterprise project. Picking MIT for all of this stuff simplifies things as much as we can.&lt;/p&gt;
&lt;h4 id=&quot;12-love-the-developer&quot;&gt;&lt;a href=&quot;#12-love-the-developer&quot; aria-label=&quot;12 love the developer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;12. Love the developer&lt;/h4&gt;
&lt;p&gt;Don’t ignore developer workflow! We’ve got a few nice things you can see in the &lt;a href=&quot;http://ampersandjs.com/learn/quick-start-guide&quot;&gt;app the cli builds&lt;/a&gt; that let you simply flip a &quot;developmentMode&quot; boolean to put your app into a live-reloaded, unminified mode, or conversely into a production mode (more below).&lt;/p&gt;
&lt;h3 id=&quot;the-problems-with-tiny-modules&quot;&gt;&lt;a href=&quot;#the-problems-with-tiny-modules&quot; aria-label=&quot;the problems with tiny modules permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The problems with tiny modules&lt;/h3&gt;
&lt;p&gt;It’s not a silver bullet. One of the biggest challenges for the &quot;tiny module approach&quot; is knowing which tiny modules exist and which ones to use. This can be quite daunting for someone who’s used to grabbing a few jQuery plugins and is new to all of this. &lt;/p&gt;
&lt;p&gt;Most of the tiny modules are, well... tiny. These are small pieces of code, not heavily marketed because they’re not necessarily the pride and joy of the developer. Many of them are rather boring and don’t do very much, plus they’re infrequently updated and often they even look unmaintained because frankly, they represent a solved problem that doesn’t need to be re-solved!&lt;/p&gt;
&lt;p&gt;Seriously, having published a ton of tiny modules, I sometimes forget about my own modules!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This can make it incredibly hard to get started and this is where frameworks really shine.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So, we’re doing a couple of things to solve that problem for ourselves and others building Ampersand.js apps.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A better starting point:&lt;/strong&gt; &lt;a href=&quot;https://github.com/ampersandjs/ampersand&quot;&gt;The ampersand cli&lt;/a&gt; is a scaffolding tool. It helps you build out a fully working starter app including a hapi or express node server to serve your application. It includes patterns and approaches that we use at &lt;a href=&quot;http://andyet.com&quot;&gt;&amp;#x26;yet&lt;/a&gt; for structuring and serving single page apps which we’ve defined in &lt;a href=&quot;http://humanjavascript.com&quot;&gt;Human JavaScript&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The tools site:&lt;/strong&gt; &lt;a href=&quot;http://tools.ampersandjs.com&quot;&gt;tools.ampersandjs.com&lt;/a&gt;. This is a site with quick-searchable, hand-picked tools for building Ampersand-style apps. A grab bag of &quot;solved problems&quot; for single page apps, if you will. In addition it updates its url as you search so it’s deep linkable. For example, if you’re looking to do WebRTC stuff: &lt;a href=&quot;http://ampersandjs.github.io/tools.ampersandjs.com/?q=webrtc&quot;&gt;http://ampersandjs.github.io/tools.ampersandjs.com/?q=webrtc&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A book describing the philosophy:&lt;/strong&gt; If you’re looking for deeper explanations of the philosophy and approaches used in the generated app, those are described in a lot more detail in my book &lt;a href=&quot;http://humanjavascript.com&quot;&gt;Human JavaScript&lt;/a&gt;, which along with releasing the framework, we’ve now made available to &lt;a href=&quot;http://read.humanjavascript.com/&quot;&gt;read online for free&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;massive-props-to-jeremy-ashkenas-and-the-rest-of-the-backbonejs-authors&quot;&gt;&lt;a href=&quot;#massive-props-to-jeremy-ashkenas-and-the-rest-of-the-backbonejs-authors&quot; aria-label=&quot;massive props to jeremy ashkenas and the rest of the backbonejs authors permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Massive props to Jeremy Ashkenas and the rest of the Backbone.js authors&lt;/h3&gt;
&lt;p&gt;Many of the individual modules contain copy-and-pasted code from Backbone.js.&lt;/p&gt;
&lt;p&gt;We’re incredibly grateful for &lt;a href=&quot;https://twitter.com/jashkenas&quot;&gt;Jeremy&lt;/a&gt;’s work and for the generous MIT licensing that made Ampersand.js possible.&lt;/p&gt;
&lt;h3 id=&quot;the-future&quot;&gt;&lt;a href=&quot;#the-future&quot; aria-label=&quot;the future permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The future&lt;/h3&gt;
&lt;p&gt;There’s still a lot to do. &lt;/p&gt;
&lt;p&gt;Now that we’ve removed our dependency on Backbone we’re free to edit other things in &quot;core&quot; that we’ve had alternate ideas about. &lt;/p&gt;
&lt;p&gt;With the flexibility that comes with the tiny modules approach, it’s easier to do a lot more exploration without having to change core items. &lt;/p&gt;
&lt;p&gt;A few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/latentflip/domthing&quot;&gt;domthing&lt;/a&gt; - &lt;a href=&quot;https://twitter.com/philip_roberts&quot;&gt;Philip Roberts&lt;/a&gt; has built an incredibly awesome DOM-based templating language and a &lt;a href=&quot;https://github.com/AmpersandJS/ampersand-domthing-mixin&quot;&gt;mixin&lt;/a&gt; to work with Ampersand.js.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/henrikjoreteg/bind-transforms&quot;&gt;bind-transforms&lt;/a&gt; - A way to elegantly bind styles like CSS transforms to models. In combination with the cached, evented, derived properties of &lt;a href=&quot;http://ampersandjs.com/docs#ampersand-state&quot;&gt;ampersand-state&lt;/a&gt; let’s you build amazing things, like smooth drag-n-drop views.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://ampersandjs.com/learn/forms&quot;&gt;ampersand-forms&lt;/a&gt; - A set of tools for building rich, interactive forms.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’d encourage you to get involved. &lt;/p&gt;
&lt;p&gt;For simplicity all the &quot;core&quot; stuff is on Github as its own organization: &lt;a href=&quot;https://github.com/ampersandjs&quot;&gt;https://github.com/ampersandjs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Send pull requests, file issues, and tell the core team that we’re wrong on twitter: &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/philip_roberts&quot;&gt;@philip_roberts&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/lynnandtonic&quot;&gt;@lynnandtonic&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/lancestout&quot;&gt;@lancestout&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/lukekarrys&quot;&gt;@lukekarrys&lt;/a&gt;, and &lt;a href=&quot;http://twitter.com/wraithgar&quot;&gt;@wraithgar&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;For more cool stuff, follow the whole &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; team on twitter.&lt;/p&gt;
&lt;h3 id=&quot;learning-even-more&quot;&gt;&lt;a href=&quot;#learning-even-more&quot; aria-label=&quot;learning even more permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Learning even more&lt;/h3&gt;
&lt;p&gt;To learn more about building advanced JavaScript applications that are as maintainable as they are awesome learn directly from the folks behind ampersand at our bound-to-be-memorable upcoming training adventure — &lt;a href=&quot;http://jsforteams.com/its-aliiiive/&quot;&gt;JS for Teams: &quot;It’s Aliiive!”&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Tickets on sale for JS for Teams: It's ALIIIIVE!]]></title><description><![CDATA[JS for Teams: It's ALIIIIVE! is a two-day training adventure happening July 24 & 25 focused on teaching teams how to build advanced single…]]></description><link>https://blog.andyet.com/2014/06/12/tickets-on-sale-for-js-for-teams-its-aliiiive/</link><guid isPermaLink="false">https://blog.andyet.com/2014/06/12/tickets-on-sale-for-js-for-teams-its-aliiiive/</guid><pubDate>Thu, 12 Jun 2014 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://jsforteams.com/its-aliiiive/&quot;&gt;JS for Teams: It&apos;s ALIIIIVE!&lt;/a&gt; is a &lt;strong&gt;two-day training adventure happening July 24 &amp;#x26; 25 focused on teaching teams how to build advanced single-page apps in a highly maintainable way&lt;/strong&gt;. &lt;a href=&quot;http://jsforteams.com/its-aliiiive/&quot;&gt;Tickets on sale today&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;To celebrate, &lt;strong&gt;we&apos;re offering $200 off per ticket for the next 5 tickets&lt;/strong&gt; – use the discount code AMPERSAND at check-out.&lt;/p&gt;
&lt;p&gt;The tickets we set aside for our email subscribers already sold out, so don&apos;t miss your chance. &lt;strong&gt;Seats are extremely limited.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://ti.to/&amp;#x26;yet/js-for-teams-its-aliiiive?release_id=sft-cw3f-zg&quot;&gt;Enroll now&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[No more rockstars — The business case for writing JavaScript as a team]]></title><description><![CDATA[Is there an inherent business risk in letting your top JavaScript developers do their best work?(What a painful thought!)It's one thing to…]]></description><link>https://blog.andyet.com/2014/06/09/no-more-rockstars/</link><guid isPermaLink="false">https://blog.andyet.com/2014/06/09/no-more-rockstars/</guid><pubDate>Mon, 09 Jun 2014 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Is there an inherent business risk in letting your top JavaScript developers do their best work?&lt;/p&gt;
&lt;p&gt;(What a painful thought!)&lt;/p&gt;
&lt;p&gt;It&apos;s one thing to build with the latest tools and techniques, but &lt;strong&gt;what happens when the developers who led the way on a given app move on to greener pastures?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;JavaScript apps are notorious for being largely written by one &quot;rockstar,&quot; ending up dominated by the most experienced JS dev, the most charismatic person, or at least by the fastest typer. &lt;/p&gt;
&lt;p&gt;And the first thing the people who inherit an app want to do is undertake a costly rewrite.&lt;/p&gt;
&lt;p&gt;How do you overcome that tendency?&lt;/p&gt;
&lt;p&gt;The problem isn&apos;t devs doing their best work. It&apos;s that &lt;strong&gt;the software they work on will outlive their attention span and maintenance capability.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;so-are-js-frameworks-the-answer&quot;&gt;&lt;a href=&quot;#so-are-js-frameworks-the-answer&quot; aria-label=&quot;so are js frameworks the answer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So, are JS frameworks the answer?&lt;/h3&gt;
&lt;p&gt;One key reason enterprises choose highly constrained tools for building with JS: less room for the kind of creativity and innovation that makes a single developer&apos;s work capable of being &lt;em&gt;both&lt;/em&gt; high return &lt;em&gt;and&lt;/em&gt; high risk.&lt;/p&gt;
&lt;p&gt;But tools like those can also disengage veteran JS developers who prefer flexibility and modularity.&lt;/p&gt;
&lt;p&gt;In my years of experience working with and managing developers, I&apos;ve learned that developers who are mentally &lt;em&gt;engaged&lt;/em&gt; are most capable of amazing work. And developers who are engaged in their work have a stronger desire to keep doing it.&lt;/p&gt;
&lt;p&gt;It&apos;s a tradeoff: the risk of losing (or depending on) a very good developer is often mitigated by the same tools that increase the likelihood they &lt;em&gt;will&lt;/em&gt; leave—or mentally check out.&lt;/p&gt;
&lt;h3 id=&quot;the-tools-that-tend-to-make-collaboration-and-consistency-easy-can-leave-very-good-developers-hamstrung&quot;&gt;&lt;a href=&quot;#the-tools-that-tend-to-make-collaboration-and-consistency-easy-can-leave-very-good-developers-hamstrung&quot; aria-label=&quot;the tools that tend to make collaboration and consistency easy can leave very good developers hamstrung permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The tools that tend to make collaboration and consistency easy can leave very good developers hamstrung.&lt;/h3&gt;
&lt;p&gt;Learning a framework provides a lot of instant gratification, but we&apos;ve seen frameworks and approaches come and go as the web has rapidly evolved. &lt;/p&gt;
&lt;p&gt;Developers who end up learning a framework instead of how to solve problems in JavaScript can limit their long-term potential.&lt;/p&gt;
&lt;p&gt;What&apos;s more, JavaScript does not lend itself well to one-size-fits-all frameworks. There are certain types of apps that make sense for certain frameworks, but it&apos;s undeniable that no JS framework is a panacea.&lt;/p&gt;
&lt;h3 id=&quot;so-how-do-we-solve-this-problem-at-yet&quot;&gt;&lt;a href=&quot;#so-how-do-we-solve-this-problem-at-yet&quot; aria-label=&quot;so how do we solve this problem at yet permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So how do we solve this problem at &amp;#x26;yet?&lt;/h3&gt;
&lt;p&gt;I&apos;d love to say we&apos;ve had this down for years, but we actually stumbled upon the answer.&lt;/p&gt;
&lt;p&gt;Our first Node.js based single-page app product, And Bang 1.0, was built largely by &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;Henrik Joreteg&lt;/a&gt; and myself; I wrote the CSS and Henrik wrote the rest of the app, both server and client.&lt;/p&gt;
&lt;p&gt;At a certain point, we decided to do a major refactor, creating And Bang 2.0. &lt;/p&gt;
&lt;p&gt;While building the API for And Bang 2.0 was a full-team effort, getting people involved in the JS app proved tremendously challenging. Folks could contribute to parts of the app, but in the end, it was fully dependent on Henrik because not enough of our team understood the approaches Henrik was taking in building the app.&lt;/p&gt;
&lt;p&gt;This presented a huge long-term risk. It wasn&apos;t good for the team, and it certainly wasn&apos;t good for Henrik. We all knew action was needed.&lt;/p&gt;
&lt;h3 id=&quot;at-one-point-i-recall-a-few-of-us-taking-henrik-out-to-a-really-painful-lunch&quot;&gt;&lt;a href=&quot;#at-one-point-i-recall-a-few-of-us-taking-henrik-out-to-a-really-painful-lunch&quot; aria-label=&quot;at one point i recall a few of us taking henrik out to a really painful lunch permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;At one point, I recall a few of us taking Henrik out to a really painful lunch.&lt;/h3&gt;
&lt;p&gt;We told him that despite being the most productive developer on the project, he was no longer allowed to write JS on the app. He could only open issues, write documentation, and educate.&lt;/p&gt;
&lt;p&gt;Soon, Henrik&apos;s work documenting the approaches he&apos;d taken on the app sparked involvement from others on the team. Things rapidly got clearer, easier to understand, simpler, more consistent.&lt;/p&gt;
&lt;p&gt;The conversations that emerged resulted in many of the philosophies and conventions he eventually explained in his book, &lt;em&gt;&lt;a href=&quot;http://humanjavascript.com&quot;&gt;Human JavaScript&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;then-something-amazing-started-happening&quot;&gt;&lt;a href=&quot;#then-something-amazing-started-happening&quot; aria-label=&quot;then something amazing started happening permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Then something amazing started happening.&lt;/h3&gt;
&lt;p&gt;Where we had previously experienced frustration getting people onboarded in working on our advanced JS apps, we suddenly started to find that from veterans to new developers, &lt;strong&gt;these apps &quot;made sense,&quot; and it started to look like collaboratively authored code was the work of one person.&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;Our team has &lt;em&gt;loved&lt;/em&gt; working this way.&lt;/p&gt;
&lt;p&gt;Here&apos;s what &lt;a href=&quot;http://twitter.com/philip_roberts&quot;&gt;Philip Roberts&lt;/a&gt; said in his first day working on one of our JS apps: &lt;strong&gt;&quot;This code is a dream. This is the most organized and understandable codebase I&apos;ve ever seen.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We released &lt;em&gt;Human JavaScript&lt;/em&gt; a year ago to great acclaim beyond our team. &lt;/p&gt;
&lt;p&gt;We&apos;ve since decided to follow it up with a highly experiential and interactive training that goes even deeper than &lt;em&gt;Human JavaScript&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;js-for-teams-its-aliiiive-will-provide-a-comprehensive-training-on-the-approaches-weve-developed-over-the-course-of-years&quot;&gt;&lt;a href=&quot;#js-for-teams-its-aliiiive-will-provide-a-comprehensive-training-on-the-approaches-weve-developed-over-the-course-of-years&quot; aria-label=&quot;js for teams its aliiiive will provide a comprehensive training on the approaches weve developed over the course of years permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;http://jsforteams.com/its-aliiiive&quot;&gt;JS for Teams: It&apos;s Aliiiive&lt;/a&gt; will provide a comprehensive training on the approaches we&apos;ve developed over the course of years.&lt;/h3&gt;
&lt;p&gt;JS for Teams will help &lt;em&gt;your&lt;/em&gt; team build complex but maintainable single-page applications with a modular JS approach.&lt;/p&gt;
&lt;h3 id=&quot;registration-is-extremely-limited-tickets-are-now-on-sale-dont-miss-out&quot;&gt;&lt;a href=&quot;#registration-is-extremely-limited-tickets-are-now-on-sale-dont-miss-out&quot; aria-label=&quot;registration is extremely limited tickets are now on sale dont miss out permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Registration is extremely limited. &lt;a href=&quot;https://ti.to/&amp;#x26;yet/js-for-teams-its-aliiiive&quot;&gt;Tickets are now on sale&lt;/a&gt;. Don&apos;t miss out!&lt;/h3&gt;
&lt;p&gt;P.S. If you&apos;re interested in custom JS for Teams training for your organization, reach out to us at &lt;a href=&quot;mailto:training@andyet.com&quot;&gt;training@andyet.com&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[WebRTC on a restricted network]]></title><description><![CDATA[A few months ago, WebRTC agitator and yeti-friend Chris Koehnke wrote an excellent blog post explaining that browser-based videochat won't…]]></description><link>https://blog.andyet.com/2014/05/29/talky-fails/</link><guid isPermaLink="false">https://blog.andyet.com/2014/05/29/talky-fails/</guid><pubDate>Thu, 29 May 2014 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A few months ago, WebRTC agitator and yeti-friend Chris Koehnke wrote an &lt;a href=&quot;http://www.chriskranky.com/webrtc-turn-restricted-network/&quot;&gt;excellent blog post&lt;/a&gt; explaining that browser-based videochat won&apos;t work 100% of the time without a little help from something called a &quot;TURN Server&quot;. As he put it:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;If you&amp;#39;re going to launch a WebRTC powered service for financial 
gain, then you need to have done everything within your power to
ensure it works reliably across as many cases as possible.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Chris was satisfied when a few simple tests worked and stopped after that. Well, he skipped the next step.
But that&apos;s reasonable because he was probably bored already (does anyone get excited about TURN servers?) and he doesn&apos;t run a WebRTC powered service himself.&lt;/p&gt;
&lt;p&gt;The next step is looking for cases where things did not work and figure out what we can do about it. But hey, we run a WebRTC service called &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt; and connection failures are frustrating, so we decided to dig a little deeper.&lt;/p&gt;
&lt;p&gt;First, we discovered that there were still browser bugs lurking here.&lt;/p&gt;
&lt;p&gt;In Firefox, TURN support didn&apos;t work on Windows at all. &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1000858&quot;&gt;This was fixed&lt;/a&gt; in less than 24 hours after we reported it, and will be part of the upcoming Firefox 30.&lt;/p&gt;
&lt;p&gt;Reporting bugs obviously helps. But seriously, with 300 WebRTC &quot;vendors&quot; out there none of them noticed this?
Maybe no one runs Windows anymore? ;-)&lt;/p&gt;
&lt;p&gt;In Chrome, if the attempt to establish a TURN/TCP connection failed (yes, there are networks where port 80 is blocked!), the JavaScript layer was never informed of that fact. It took a little longer between &lt;a href=&quot;https://code.google.com/p/webrtc/issues/detail?id=3249&quot;&gt;our initial report and the fix&lt;/a&gt;, but again the responsiveness of the team was pretty awesome. Not for the first time.&lt;/p&gt;
&lt;p&gt;With those bugs fixed, we got to thinking: once we know that a peer-to-peer connection does not work, is there a way to determine why and tell the user about it?  It turns out that the information we get from the browser is sufficient to determine whether you can make a connection with any of our TURN servers. When the browser tells us that the connection fails, we can compare the information we receive from both you and your peer. This enables us to determine which network is responsible for this failure - which enables you, dear user, to take action.&lt;/p&gt;
&lt;p&gt;Admit it, you&apos;re bored too, aren&apos;t you?&lt;/p&gt;
&lt;p&gt;Well, here&apos;s the exciting part.&lt;/p&gt;
&lt;p&gt;Yes, it&apos;s frustrating that sometimes Talky may still fail to establish a connection between you and your peer (currently less than 5% of calls). However, as of today Talky tells you that things have failed, and also tells you which end of the connection is the likely culprit. Plus we&apos;ve improved the &lt;a href=&quot;https://talky.io/help/connectivity&quot;&gt;help page&lt;/a&gt; to describe some steps you might take to make it work.&lt;/p&gt;
&lt;p&gt;Which means today the Internet just might be a slightly happier place than it was yesterday. :-)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[^Lift Security gets reinforced by Tom Steele]]></title><description><![CDATA[Our partners in the opposite of crime ^Lift Security, are proud to welcome their newest member to our team, builder and breaker of things…]]></description><link>https://blog.andyet.com/2014/05/20/lift-reinforced-by-steele/</link><guid isPermaLink="false">https://blog.andyet.com/2014/05/20/lift-reinforced-by-steele/</guid><pubDate>Tue, 20 May 2014 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Our partners in the opposite of crime &lt;a href=&quot;https://liftsecurity.io&quot;&gt;^Lift Security&lt;/a&gt;, are proud to welcome their newest member to our team, builder and breaker of things, &lt;a href=&quot;https://twitter.com/_tomsteele&quot;&gt;Tom Steele&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Besides having the coolest name ever, Tom brings his knowledge of varied languages, passion for &lt;a href=&quot;https://github.com/tomsteele&quot;&gt;open source work&lt;/a&gt;, and a strong desire to help empower developer communities through security education and collaboration. &lt;/p&gt;
&lt;p&gt;His experience creating the open source project &lt;a href=&quot;http://www.defcon.org/images/defcon-21/dc-21-presentations/Steele-Kottman/DEFCON-21-Steele-Kottman-Collaborative-Penetration-Testing-With-Lair.pdf&quot;&gt;Lair&lt;/a&gt; as well as his early enthusiasm and contributions for the &lt;a href=&quot;https://nodesecurity.io/&quot;&gt;Node Security Project&lt;/a&gt; are just two of the many reasons we’re glad he joined the ^Lift team. &lt;/p&gt;
&lt;p&gt;We’re very excited to have Tom onboard, and for all of the awesome things he’s going to do with the team to help push ^Lift Security to the next level. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[It’s your last chance for Something Greater than Artifice]]></title><description><![CDATA[Last October, Mike Speegle introduced us to the world of the Tech Republic and the narrative behind RealtimeConf 2013 in his novel…]]></description><link>https://blog.andyet.com/2014/05/01/last-call-for-sgta/</link><guid isPermaLink="false">https://blog.andyet.com/2014/05/01/last-call-for-sgta/</guid><pubDate>Thu, 01 May 2014 16:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Last October, &lt;a href=&quot;https://www.twitter.com/mike_speegle&quot;&gt;Mike Speegle&lt;/a&gt; introduced us to the world of the Tech Republic and the narrative behind &lt;a href=&quot;http://2013.realtimeconf.com&quot;&gt;RealtimeConf 2013&lt;/a&gt; in his novel, “Something Greater than Artifice.” The book is now available in its entirety for free download at &lt;a href=&quot;http://realtimeconf.com/novel&quot;&gt;RealtimeConf.com&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Download your copy on Kindle, ePub, or PDF before &lt;strong&gt;Monday, May 5&lt;/strong&gt; when it will only be available for purchase on &lt;a href=&quot;http://www.amazon.com/Something-Greater-than-Artifice-Speegle-ebook/dp/B00FUF8X0Y/ref=sr_1_1?ie=UTF8&amp;#x26;qid=1398959136&amp;#x26;sr=8-1&amp;#x26;keywords=something+greater+than+artifice&quot;&gt;Amazon&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you haven‘t explored the world of “Something Greater than Artifice” here’s what people are saying:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“[Something Greater than Artifice] examines in a new way the implications of our use of technology, while still remaining hopeful–something that is often forgotten in futuristic novels.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;
&lt;blockquote&gt;
&lt;p&gt;“Allegory is a beautiful tool to help us understand reality and Mike has employed it masterfully.” &lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;
&lt;blockquote&gt;
&lt;p&gt;“I enjoyed immensely, and will definitely read again.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- --&gt;
&lt;p&gt;Remember, free downloads end Monday, May 5! &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Something Greater Than Artifice: the complete novel now released]]></title><description><![CDATA[the cover of the novelWe are thrilled to release "Something Greater than Artifice", a tremendous work created by our friend and colleague…]]></description><link>https://blog.andyet.com/2014/04/23/something-greater-than-artifice-the-complete-novel/</link><guid isPermaLink="false">https://blog.andyet.com/2014/04/23/something-greater-than-artifice-the-complete-novel/</guid><pubDate>Wed, 23 Apr 2014 11:15:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://i.cloudup.com/LabL-qXe4B-3000x3000.jpeg&quot; alt=&quot;the cover of the novel&quot;&gt;&lt;/p&gt;
&lt;p&gt;We are thrilled to release &quot;Something Greater than Artifice&quot;, a tremendous work created by our friend and colleague, &lt;a href=&quot;http://twitter.com/mike_speegle&quot;&gt;Mike Speegle&lt;/a&gt;. It&apos;s &lt;a href=&quot;http://realtimeconf.com/novel/&quot;&gt;now available on all kinds of media&lt;/a&gt;. (The beautiful cover was designed by &lt;a href=&quot;http://twitter.com/amydearest&quot;&gt;Amy Lynn Taylor&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Mike put months of effort into the first half of the novel, which was released in serial form in advance of &lt;a href=&quot;http://realtimeconf.com&quot;&gt;RealtimeConf&lt;/a&gt;, where the story was concluded as a live stage play.&lt;/p&gt;
&lt;p&gt;Immediately after RealtimeConf, Mike went to work concluding the novel. The ending has so much more than was visible in the play at the conference. I highly recommend reading it. &lt;/p&gt;
&lt;p&gt;The conclusion is so dramatically powerful that it brought me to tears each of the times I read it while providing feedback on Mike&apos;s drafts. More than that, it&apos;s timely for all the pain and problems that exist within the tech community (heck, even the world). &lt;/p&gt;
&lt;p&gt;It really was a privilege to get to work alongside Mike as an encourager and collaborator as he created this incredible work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So why would &amp;#x26;yet put so much investment into a novel?&lt;/strong&gt; I tried to answer that question in the book&apos;s foreword:&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The web isn&apos;t for web developers.&lt;/p&gt;
&lt;p&gt;It&apos;s for everyone.&lt;/p&gt;
&lt;p&gt;But those of us who consider ourselves &quot;from the Internet&quot; have an important role to play.&lt;/p&gt;
&lt;p&gt;My friend &lt;a href=&quot;http://twitter.com/janl&quot;&gt;Jan Lehnardt&lt;/a&gt; has put it well: developers have power as great as alchemy—we truly create gold from inexpensive materials, primarily applying only knowledge of technology.&lt;/p&gt;
&lt;p&gt;What will we do with that ever growing power?&lt;/p&gt;
&lt;p&gt;Our company, &amp;#x26;yet, believes that the world of the future can be one of greater humanity, creativity, kindness, generosity, and freedom—but the same tools at hand to create a better world are the same ones we may wield to ever more efficiently make it worse.&lt;/p&gt;
&lt;p&gt;This novel is a call for pragmatic idealists to make a difference in the small ways that really matter.&lt;/p&gt;
&lt;p&gt;There is &lt;em&gt;always&lt;/em&gt; something greater.&lt;/p&gt;
&lt;p&gt;We can be something greater than the small, selfish, fearful version of ourselves.&lt;/p&gt;
&lt;p&gt;Our relationships can be something greater than pettiness, jealousy, comparison, and competition.&lt;/p&gt;
&lt;p&gt;Our organizations can be something greater than machines that turn humans into crushable, expendable cogs.&lt;/p&gt;
&lt;p&gt;And no matter how hopeless or impossible things might seem, there is nothing ever stopping us from making things better than they are right now.&lt;/p&gt;
&lt;p&gt;I am incredibly proud to have played a small role in this beautiful piece of art Mike has created. From the very beginning, I have been blown away at the story he has woven from the bizarre set of thoughts initially presented to him. Allegory is a beautiful tool to help us understand reality and Mike has employed it masterfully.&lt;/p&gt;
&lt;p&gt;I am additionally grateful to the people who inspired and gave life to these characters, most especially Mike himself, &lt;a href=&quot;http://twitter.com/lanihendy&quot;&gt;Alana Henderson&lt;/a&gt;, and &lt;a href=&quot;http://twitter.com/eranhammer&quot;&gt;Eran Hammer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I hope you &lt;a href=&quot;http://realtimeconf.com/novel/&quot;&gt;read this work&lt;/a&gt; and ask yourself: &lt;em&gt;&quot;What&apos;s something greater for me?&quot;&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Experience the world of RealtimeConf all over again]]></title><description><![CDATA[RealtimeConf may be over, but now the experience can live on somewhere other than in the hearts and minds of the people who were there…]]></description><link>https://blog.andyet.com/2014/04/22/experience-the-world-of-realtimeconf/</link><guid isPermaLink="false">https://blog.andyet.com/2014/04/22/experience-the-world-of-realtimeconf/</guid><pubDate>Tue, 22 Apr 2014 13:00:00 GMT</pubDate><content:encoded>&lt;p&gt;RealtimeConf may be over, but now the experience can live on somewhere other than in the hearts and minds of the people who were there: &lt;a href=&quot;http://realtimeconf.com&quot;&gt;RealtimeConf.com&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Over the past few months, our team has collected memories from the &lt;a href=&quot;http://realtimeconf.com/experience/&quot;&gt;ambitious event&lt;/a&gt;, recorded the original &lt;a href=&quot;http://realtimeconf.com/music/&quot;&gt;music&lt;/a&gt; featured there, and discovered the fates of Ros and Gregor in the phenomenal conclusion to Mike Speegle’s novel, &lt;a href=&quot;http://realtimeconf.com/novel/&quot;&gt;Something Greater than Artifice&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We’ve even started planning our next epic adventure, &lt;a href=&quot;http://jsforteams.com&quot;&gt;JS for Teams&lt;/a&gt;, sign up &lt;a href=&quot;https://confirmsubscription.com/h/r/29405574CAB552E8&quot;&gt;here&lt;/a&gt; to find out about pre-registration. &lt;/p&gt;
&lt;p&gt;It &lt;em&gt;was&lt;/em&gt; a long road to the Tech Republic, so we hope you enjoy the trip down memory lane, &lt;em&gt;and&lt;/em&gt; that you’ll join us on our future treks around the universe. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[The first Node.js secure development training is coming to Portland]]></title><description><![CDATA[In just a few weeks on April 30th, the ^lift security team will host their first secure development training on building secure Node.js web…]]></description><link>https://blog.andyet.com/2014/04/18/Node-Security-Training/</link><guid isPermaLink="false">https://blog.andyet.com/2014/04/18/Node-Security-Training/</guid><pubDate>Fri, 18 Apr 2014 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f498d7f35e2be950a14844cdda901527/1d180/NST-Logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 405px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 88.74172185430463%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAABcSAAAXEgFnn9JSAAADA0lEQVQ4y7VUWU8TURTuP3B7IDFxiSAhJoYYNUSNonEhxAd9M3EBgiTi8qDRBx9cEmRJAZUHEQtEUFFAaKFIIAIhbII0SJAqUZEW2kIXOkyhC11m5vPOlA4zlFdPMg/33DPf/c7yHQXHcYgYx7Dg2PBZ6icnSI0ldyy3GieNVQhOAsKFWNHp757CfGo16OxmsDM0xgPA9T47rrRboLP5xDiGjQZWSIFCk04sZGng2PwEvqMq0AnP4I9/ClV2G1JqDTjZZUf8WwPuD9hhdgdlwDKGrGsZ7oIe2LYp4SYA3pIvqBuncFH1E9qz7+GNyYM9qQzWej1K9C4kaszYX2vEKz0Nb5CVM1xW/4DzQCmsW3Lhu92K0VEbLg9RiKsx4kK3HUN0EKFeA6iUKlCEeehSHX4NWXBnyIm46imktpjRZfKIoApHbDGcyRUIDJsEZ9bAPPbVGND0d4mPEFvC19lT9Q1zMfnw39AK/n6LF6ebTUhWz8DPhGMVjh1F8JAUBQsySP88i8wuq6w+0jpTp15jIVMNZuWsHHHiSKMMsBBuZW/kb6R3ziGNfJykLpGx4IGp45VwXdUg8kSubj3Awr4oQHECpYCEbRhQLQM8/P8Bi1YAQwwyOq0CaEQR0rR5JVEnwilHapgXlfJ2CUNivBrSOlYZhng1SJtCGFLpjeKZZ3ioYQbLTDhG4Tz4EvzoeEq/AgEG98Zc2P1mCo8HHbBK1BCYpkHfbIFtQw64Bx3gJ+/FGIXED0acb7UguKIWRWjCDhd50boxB3RyOWY1E1CO09jbZEFSsxlVf5bgKhuGZyfJJK4YPjIR2rF5nPlkER6+S2RoXAyuDra4EDom4ST1oTYRNWQ2Qt9txLXKCcS+MyA1fwRtt9owOmBGxvACdvEqap/FoNUna57AULayyGB7VDrYEp5jcWsBXKRhrY96cK7fiQTtLPY0mHDs4zTqfy+KW2btKlOIoyEpPDNH0nzYCU+5DvAGECB3Fd8XUExUQS0zchVFrS9ujVMCLPyEaFsPKGL/AK+B8XnquIxTAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;node security training logo&quot;
        title=&quot;&quot;
        src=&quot;/static/f498d7f35e2be950a14844cdda901527/1d180/NST-Logo.png&quot;
        srcset=&quot;/static/f498d7f35e2be950a14844cdda901527/29fe9/NST-Logo.png 151w,
/static/f498d7f35e2be950a14844cdda901527/6728c/NST-Logo.png 303w,
/static/f498d7f35e2be950a14844cdda901527/1d180/NST-Logo.png 405w&quot;
        sizes=&quot;(max-width: 405px) 100vw, 405px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In just a few weeks on April 30th, the &lt;a href=&quot;https://liftsecurity.io&quot;&gt;^lift security&lt;/a&gt; team will host their first secure development training on &lt;a href=&quot;https://ti.to/lift-security/node-sec-dev-portland&quot;&gt;building secure Node.js web applications&lt;/a&gt; in Portland, Oregon.&lt;/p&gt;
&lt;p&gt;The ^lift team has designed this training to help you understand the security challenges you will face when developing Node.js web applications and help you build habits that turn security from a worry or an annoyance, into a comfortable part of writing your code from the very beginning.&lt;/p&gt;
&lt;p&gt;Seats at this first class are extremely limited, so grab your spot with the team that’s been trusted to secure tools you use everyday like npm, Github and Ginger, as well as leads the &lt;a href=&quot;https://nodesecurity.io/&quot;&gt;Node Security Project&lt;/a&gt;. Also &lt;a href=&quot;https://ti.to/lift-security/node-sec-dev-portland&quot;&gt;discounted tickets&lt;/a&gt; are available if you want to bring your dev team (or hack the system and bring a couple friends, we won’t tell anyone).&lt;/p&gt;
&lt;p&gt;If you can’t attend this training and you would like the ^lift team to bring it to your area, or even bring it to your dev team, please let us know by sending an email to &lt;a href=&quot;mailto:training@liftsecurity.io&quot;&gt;training@liftsecurity.io&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ti.to/lift-security/node-sec-dev-portland&quot;&gt;Tickets! Tickets! Get your tickets now!&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Heartbleed happened]]></title><description><![CDATA[So Heartbleed happened, and if you’re a company or individual who has public facing assets that are behind anything using OpenSSL, you need…]]></description><link>https://blog.andyet.com/2014/04/09/heartbleed-happened/</link><guid isPermaLink="false">https://blog.andyet.com/2014/04/09/heartbleed-happened/</guid><pubDate>Wed, 09 Apr 2014 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So &lt;a href=&quot;http://heartbleed.com/&quot;&gt;Heartbleed&lt;/a&gt; happened, and if you’re a company or individual who has public facing assets that are behind &lt;em&gt;anything&lt;/em&gt; using OpenSSL, you need to respond to this now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sslimgs.xkcd.com/comics/heartbleed.png&quot; alt=&quot;xkcd comic about heartbleed&quot;&gt;&lt;/p&gt;
&lt;p&gt;The first thing we had to do at &amp;#x26;yet was determine what was actually impacted by this disclosure. We had to make list of what services are public facing, which services use OpenSSL directly or indirectly, and which services use keys/tokens that are cryptographically generated. It’s easy to only update your web servers, but really that is just one of many steps.&lt;/p&gt;
&lt;p&gt;Here is a list of what you can do to respond to this event.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Upgrade your servers to have the most recent version of OpenSSL, specifically version v1.0.1g, installed. The list of OS packages which have that version are too numerous to list so double check with your package manager for what version is appropriate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Restart any instance of Nginx, Apache, HAproxy, Varnish, XMPP Server or any other tool that dynamically links to OpenSSL. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For any public facing service you are running that statically links to OpenSSL (or one of its libraries) you will need to rebuild the code and deploy. For us that was “restund” which we use for STUN/TURN.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For any authentication database you have that uses OAuth tokens or cryptographically generated keys, you should mark all of those tokens and keys as invalid and force them to be regenerated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Any public facing SSL Certificate you have should be revoked and new certificates with new keys generated as well.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The last two items can be somewhat daunting, since due to the nature of this exploit we don’t know if our certs or keys (or really anything in memory) were compromised. The responsible thing to do is to assume that they were compromised, and replace them.&lt;/p&gt;
&lt;h2 id=&quot;security-bulletins&quot;&gt;&lt;a href=&quot;#security-bulletins&quot; aria-label=&quot;security bulletins permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Security Bulletins:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160&quot;&gt;Mitre CVE for Heartbleed CVE-2014-0160&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.openssl.org/news/secadv_20140407.txt&quot;&gt;OpenSSL Security Advisory 20140407&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.ubuntu.com/usn/usn-2165-1/&quot;&gt;Ubuntu Security Notice USN-2165-1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rhn.redhat.com/errata/RHSA-2014-0376.html&quot;&gt;RedHat Security Advisory RHSA-2014:0376-1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lists.fedoraproject.org/pipermail/announce/2014-April/003205.html&quot;&gt;Fedora Project Announcment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.spinics.net/lists/centos-announce/msg04910.html&quot;&gt;CentOS Announcement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://security-tracker.debian.org/tracker/CVE-2014-0160&quot;&gt;Debian Security Tracker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;resources&quot;&gt;&lt;a href=&quot;#resources&quot; aria-label=&quot;resources permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Resources:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openssl/openssl/commit/7e840163c06c7692b796a93e3fa85a93136adbb2&quot;&gt;OpenSSL Git Commit for CVE-2014-0160&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nginx.com/blog/nginx-and-the-heartbleed-vulnerability/&quot;&gt;NGINX and the Heartbleed vulnerability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serverfault.com/questions/587551/my-server-is-still-vulnerable-to-heartbleed-even-after-i-update-openssl&quot;&gt;serverfault: My server is still vulnerable to heartbleed even after I update OpenSSL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://access.redhat.com/site/solutions/781793&quot;&gt;RedHat Support Article for OpenSSL CVE-2014-0160&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bugzilla.redhat.com/show_bug.cgi?id=1084875&quot;&gt;RedHat Security Response Bug&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Nerdsniping: A glimpse into a stubborn mind]]></title><description><![CDATA[The setupEleven days ago, Jon Lamendola was asking Adam Baldwin in our team chat how to do something with JavaScript. The discussion went…]]></description><link>https://blog.andyet.com/2014/04/07/nerdsniping/</link><guid isPermaLink="false">https://blog.andyet.com/2014/04/07/nerdsniping/</guid><pubDate>Mon, 07 Apr 2014 11:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-setup&quot;&gt;&lt;a href=&quot;#the-setup&quot; aria-label=&quot;the setup permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The setup&lt;/h2&gt;
&lt;p&gt;Eleven days ago, &lt;a href=&quot;http://andyet.com/team/ljon&quot;&gt;Jon Lamendola&lt;/a&gt; was asking &lt;a href=&quot;http://andyet.com/team/baldwin&quot;&gt;Adam Baldwin&lt;/a&gt; in our team chat how to do something with JavaScript. The discussion went like this:&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0bf546c7e4183dde837a30d7a823cf1b/6b9fd/2014-04-07-nerdsniping-chatlog.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 518px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 95.36423841059603%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAACXBIWXMAAAsSAAALEgHS3X78AAACpklEQVQ4y4VU207bUBD0//8HUgVqH6BqoaIFAqlQITcSAb0AiZM4vt+TEKg03VnbIYEiHlabc2KNZ2dmbWxsvMPOzifcPzzC8wPYjqfd9XyMLBu262E4tuAHISa2K/+FiNIMfpQgiNMXZVx0e7i6/ok0n8EPIzgCZLtFTQTcFfDxxCnPrp7DJH0dsNM4w9HXfeTze4RRjCDJXjwUyl1VPL8GpoBXl5dot1qYLx6QZjniNEdS9qIEqAR5qxSw12nh5PAQ6XSOvjmU8WxYUtTNsmVUGTOT//wVts/ZV52gxvbHz/h2UMPi8S8CGTmKE61QKhatKIMnhgRhrHd+EBXSlEVNg/KZNJ/CqB3XcXbeRD6bKyM+QPHpNp0mY9cLSraesHfUeT5jiesja6LumyNL5TEuux2cHteQze7hqLueOk0WBOFvR+749iDO1gxiRaJz1X3VsNdDs9EodBLa1UiRjEu21ZmANCl4wyCj126KKQdIJIdjCfJEWI3GEw133xzpyBzrtm9iIGcmwHvF4UA0Ng6PjlH/fqqbkogGaZ4jEzYsxqjqBKo6tXqq4ryMzbas3VHtREe6GwxV3EJwR9mxbvsD3NwNlmwZKUZsMBxrp/uVFMbNr2u0G+eyKYsiDrJ+XEGNjpyTbFqK/tyMqvK17TFazSbqJ3VMZfUY6IKZs9zjbDp7CVKG+LmGynBz8z32vuzr6tEIxoTsyJSjqwSSM97zZSzeF7o9bcyS4Q8Jdfuip8EmCMfUDeFWyJkbUEiQanfl8+UxSssvzvqHwtja+oDd3T0d2RSRGRmWORoX+yzjM078jw4rm9UsrrDTkX//ucHtwFTAtcjkTzFJy+jESRGV/31glyN3L1oSWFPzNBRWjAXjQe3MMhbsDDajw+DzJauAqwz/AW2yjFesHZHvAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Chat discussion&quot;
        title=&quot;&quot;
        src=&quot;/static/0bf546c7e4183dde837a30d7a823cf1b/6b9fd/2014-04-07-nerdsniping-chatlog.png&quot;
        srcset=&quot;/static/0bf546c7e4183dde837a30d7a823cf1b/29fe9/2014-04-07-nerdsniping-chatlog.png 151w,
/static/0bf546c7e4183dde837a30d7a823cf1b/6728c/2014-04-07-nerdsniping-chatlog.png 303w,
/static/0bf546c7e4183dde837a30d7a823cf1b/6b9fd/2014-04-07-nerdsniping-chatlog.png 518w&quot;
        sizes=&quot;(max-width: 518px) 100vw, 518px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;A quick aside for any non devs&lt;/strong&gt;, the longer version of what Baldwin could have written was:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;if (b==1 &amp;amp;&amp;amp; b===2 &amp;amp;&amp;amp; b===herpderp) {
   // do stuff here
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is an if-statement in JavaScript. JavaScript checks the “condition,” which is the code between the first set of ( parenthesis ), and if, and only-if it is true, runs the code between the { curly braces }.&lt;/p&gt;
&lt;p&gt;The == / === are like an equals sign in math, they check if b is equal to 1, b is equal to 2, and b is equal to herpderp.&lt;/p&gt;
&lt;p&gt;b and herpderp are just placeholders for other values, they could be anything, depending on what code was written before these lines.&lt;/p&gt;
&lt;p&gt;Finally &amp;#x26;&amp;#x26; means “and.” So in this case, for the condition to be true, b must equal 1 AND b must equal 2 AND b must equal herpderp.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;At first glance, what Jon said seems to be true. Whatever &lt;code class=&quot;language-text&quot;&gt;b&lt;/code&gt; is, it can’t be both equal to &lt;code class=&quot;language-text&quot;&gt;1&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;2&lt;/code&gt; at the same time, so the condition can never be true, and the code inside &lt;code class=&quot;language-text&quot;&gt;{ }&lt;/code&gt; will never execute.&lt;/p&gt;
&lt;p&gt;However, it is at this moment I realise I am well and truly screwed. Jon has used two words which &lt;em&gt;always&lt;/em&gt; get me: “can’t” and “never.” Something in the back of my mind niggles: what he said is basically true, but I am also pretty sure there’s a way that someone could break JavaScript subtly enough to make it not true. And I know it’s going to bother me until I can figure it out. This leads to my single contribution to the conversation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phil&lt;/strong&gt;: Oh man, you’ve totally nerdsniped me.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you haven’t heard the term nerdsniping before, this &lt;a href=&quot;http://xkcd.com&quot;&gt;xkcd&lt;/a&gt; comic lays it out pretty well:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://sslimgs.xkcd.com/comics/nerd_sniping.png&quot; alt=&quot;xkcd nerdsniping comic&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;attempt-one--vs-&quot;&gt;&lt;a href=&quot;#attempt-one--vs-&quot; aria-label=&quot;attempt one  vs  permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Attempt one, == vs ===&lt;/h2&gt;
&lt;p&gt;I immediately pull up a text editor and start to experiment with how I can possibly get something to equal one and two at the same time.&lt;/p&gt;
&lt;p&gt;The first thing my brain latches onto is the possibility of exploiting a typo in Baldwin’s code. He wrote &lt;code class=&quot;language-text&quot;&gt;b==1 &amp;amp;&amp;amp; b===2&lt;/code&gt; (note 2 = vs 3 =). This is still valid JavaScript, and they both mean roughly the same thing, but &lt;code class=&quot;language-text&quot;&gt;==&lt;/code&gt; is subtly different from &lt;code class=&quot;language-text&quot;&gt;===&lt;/code&gt;. Roughly, &lt;code class=&quot;language-text&quot;&gt;===&lt;/code&gt; checks if two things are the &lt;em&gt;same thing&lt;/em&gt;, while &lt;code class=&quot;language-text&quot;&gt;==&lt;/code&gt; checks if two things are “equivalent.”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Checking if &lt;em&gt;something&lt;/em&gt; is exactly equal to &lt;code class=&quot;language-text&quot;&gt;2&lt;/code&gt; is easy, first we check if &lt;em&gt;something&lt;/em&gt; is a number, and if it is we check if it’s the number 2. If so, then yes &lt;em&gt;something&lt;/em&gt; === 2. If it&apos;s not a number then it can&apos;t possibly be exactly equal to 2, no matter what it is.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;But checking if &lt;em&gt;something&lt;/em&gt; is “equivalent” to &lt;code class=&quot;language-text&quot;&gt;1&lt;/code&gt; is more tricky. If &lt;em&gt;something&lt;/em&gt; is a number then we just check if it is the number 1. But if it’s not a number, it still might be “equivalent” to 1. To figure it out if &lt;em&gt;something&lt;/em&gt; is equivalent to 1, JavaScript calls the &lt;code class=&quot;language-text&quot;&gt;valueOf()&lt;/code&gt; method on &lt;em&gt;something&lt;/em&gt;, and if &lt;em&gt;that&lt;/em&gt; returns 1, then &lt;em&gt;something&lt;/em&gt; == 1.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I did some experiments, here are just a few of the more interesting things I tried:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I started by verifying that &lt;code class=&quot;language-text&quot;&gt;valueOf&lt;/code&gt; works like I expected for == comparisons: If I start with a b that is just a random thing, I can change it’s valueOf function, and have it return 1, which works.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//a something&lt;/span&gt;

b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;valueOf&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;This code is executed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//yup, this works&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I then think, ah ha, I can just start with a 2, and change &lt;em&gt;it’s&lt;/em&gt; valueOf function to return 1, but that doesn’t seem to work :(&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;var b = 2;

b.valueOf = function () {
    return 1;
};

if (b==1) {
    console.log(&amp;#39;This aint called&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then I remember that there are two slightly different ways to declare a number in JavaScript: &lt;code class=&quot;language-text&quot;&gt;var b = 1&lt;/code&gt; is different to &lt;code class=&quot;language-text&quot;&gt;var b = new Number(1)&lt;/code&gt;. Ah ha! Maybe I change the prototype? And it works. Welp, I’ve just made a number 2, that is equivalent to 1. Way to break things! But breaking things is what I’m trying to do, so I guess that’s a win.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Number.prototype.valueOf = function () {
    return 1;
};

var b = new Number(2);

if (b==1) {
    console.log(&amp;#39;This is called&amp;#39;); //Woo!
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alas now, &lt;code class=&quot;language-text&quot;&gt;b===2&lt;/code&gt; is no longer true. I guess we’ve messed with the prototype too much, and JavaScript isn’t really convinced it’s still a proper number anymore.&lt;/p&gt;
&lt;h2 id=&quot;attempt-two-read-the-specs&quot;&gt;&lt;a href=&quot;#attempt-two-read-the-specs&quot; aria-label=&quot;attempt two read the specs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Attempt two, read the specs&lt;/h2&gt;
&lt;p&gt;A few days pass. And the problem comes back to mind. I start digging in even further to the difference between == and === to see how I might be able to exploit it. A question on  &lt;a href=&quot;stackoverflow.com&quot;&gt;stackoverflow.com&lt;/a&gt; discussing the differences between the two, links to the &lt;a href=&quot;http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf&quot;&gt;original specification pdf document for JavaScript&lt;/a&gt;. Yes, thanks Jon, at this point I am now reading the ecmascript spec in pursuit of pedantry.&lt;/p&gt;
&lt;p&gt;What’s possibly amusing is I’ve been a JavaScript developer for a number of years, and this is the first time I’ve ever even &lt;em&gt;opened&lt;/em&gt; the spec document.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I read &lt;strong&gt;11.9.3 The Abstract Equality Comparison Algorithm&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;I read &lt;strong&gt;11.9.6 The Strict Equality Comparison Algorithm&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;I read &lt;strong&gt;9.3 ToNumber&lt;/strong&gt; and &lt;strong&gt;9.3.1 ToNumber Applied to the String Type&lt;/strong&gt; as they were mentioned by the Abstract Equality Comparison Algorithm.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I read those, and spend another hour or so hacking and experimenting, but alas, nothing of interest is revealed. To make &lt;code class=&quot;language-text&quot;&gt;b===2&lt;/code&gt; b has to be a number, but to make &lt;code class=&quot;language-text&quot;&gt;b==1&lt;/code&gt; I have to modify b&apos;s &lt;code class=&quot;language-text&quot;&gt;valueOf&lt;/code&gt; method, which immediately makes it not a proper number anymore.&lt;/p&gt;
&lt;p&gt;Frustrated I give it up for the day. I’m still pretty sure it’s doable, but I just haven’t seen how yet.&lt;/p&gt;
&lt;h2 id=&quot;11-days-later-success&quot;&gt;&lt;a href=&quot;#11-days-later-success&quot; aria-label=&quot;11 days later success permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;11 days later... SUCCESS!&lt;/h2&gt;
&lt;p&gt;Eleven days after the original post, and I’ve all but forgotten about my little nerdsnipe failure.&lt;/p&gt;
&lt;p&gt;I&apos;m sitting reading &lt;a href=&quot;http://raganwald.com/2014/03/31/class-hierarchies-dont-do-that.html&quot;&gt;a post by Reginald Braithwaite&lt;/a&gt;. I always enjoy Reg’s writing because he likes to break JavaScript down to its components and think about how and why it works. And somehow reading this post, and thinking about Reg, reminds me of my little problem.&lt;/p&gt;
&lt;p&gt;I fire up a text editor again. For some reason the answer, this time, is obvious immediately.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;var b = {};
var herpderp = 2;

b.valueOf = function () {
    b = 2;
    return 1;
};

if (b==1 &amp;amp;&amp;amp; b===2 &amp;amp;&amp;amp; b===herpderp) {
    console.log(&amp;#39;This code runs!!!&amp;#39;);
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I run it, it works, success! So how does it work? Well first of all I had to realise the one little mistake in Jon’s phrasing. He said “b can&apos;t be 1, 2 and herpderp at the same time, so that code would never execute.” But that’s not quite what’s happening here. It’s not happening “at the same time”: &lt;em&gt;first&lt;/em&gt; JavaScript checks if &lt;code class=&quot;language-text&quot;&gt;b==1&lt;/code&gt;, &lt;em&gt;then&lt;/em&gt; it checks if &lt;code class=&quot;language-text&quot;&gt;b===2&lt;/code&gt; and &lt;em&gt;then&lt;/em&gt; it checks if &lt;code class=&quot;language-text&quot;&gt;b===herpderp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First we make &lt;code class=&quot;language-text&quot;&gt;b&lt;/code&gt; something that is not a number, but give it a &lt;code class=&quot;language-text&quot;&gt;valueOf&lt;/code&gt; function that returns 1, such that &lt;code class=&quot;language-text&quot;&gt;b==1&lt;/code&gt; calls the &lt;code class=&quot;language-text&quot;&gt;valueOf&lt;/code&gt; function, sees that it got a 1 back, and this passes the first test. But we also did something sneaky in that valueOf function call, we changed b to be the number 2. Now when JavaScript gets to the next check, &lt;code class=&quot;language-text&quot;&gt;b===2&lt;/code&gt;, it sees that b is 2, and that passes. Finally it gets to &lt;code class=&quot;language-text&quot;&gt;b===herpderp&lt;/code&gt;, which is easy as we can make herpderp whatever we like, so if we make it 2, we&apos;re all good and all three tests pass.&lt;/p&gt;
&lt;p&gt;It should be noted, that I got very lucky. If Baldwin hadn’t missed that third = off the first check, or even if he’d put the two-= in one of the other checks instead, this solution wouldn’t have worked.&lt;/p&gt;
&lt;h2 id=&quot;and-there-we-have-it&quot;&gt;&lt;a href=&quot;#and-there-we-have-it&quot; aria-label=&quot;and there we have it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;And there we have it&lt;/h2&gt;
&lt;p&gt;Eleven days later, and that little nerdsnipe can slip from my mind. Have I learned anything directly useful? Probably not. Have I learned something that might come in handy one day? Just maybe I’ll have a handy little tool I can use to pick away at some particularly fiddly bug. Or maybe, my next nerdsnipe will be a little easier to solve. At the very least I now know where the ecmascript spec document is!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;postscript&quot;&gt;&lt;a href=&quot;#postscript&quot; aria-label=&quot;postscript permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Postscript:&lt;/h2&gt;
&lt;p&gt;After realising it had taken me &lt;em&gt;11 days&lt;/em&gt; to solve this nerdsnipe, I threw it out to twitter and got &lt;a href=&quot;https://twitter.com/jaz303/statuses/450383462466609152&quot;&gt;a hint from @jaz303&lt;/a&gt; about another way of solving this that would have worked &lt;em&gt;even if Baldwin hadn’t typo’d that first ===&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; herpderp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;global&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function-variable function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; n&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b&lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; b&lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt;herpderp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;this runs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here, instead of creating a local variable b with &lt;code class=&quot;language-text&quot;&gt;var b&lt;/code&gt;, we are defining a property on the &lt;code class=&quot;language-text&quot;&gt;global&lt;/code&gt; object (in the browser this would be &lt;code class=&quot;language-text&quot;&gt;window&lt;/code&gt;). The way that JavaScript looks up variable references, means that if it can’t find a local variable named &lt;code class=&quot;language-text&quot;&gt;b&lt;/code&gt; it will try it on the global object: so &lt;code class=&quot;language-text&quot;&gt;b===1&lt;/code&gt; is the same as &lt;code class=&quot;language-text&quot;&gt;global.b===1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also, instead of just defining &lt;code class=&quot;language-text&quot;&gt;global.b = 1&lt;/code&gt;, we’ve defined it using &lt;code class=&quot;language-text&quot;&gt;Object.defineProperty()&lt;/code&gt;, this allows us to create a getter which increments the returned value every time it is called, allowing all three tests to pass if &lt;code class=&quot;language-text&quot;&gt;herpderp&lt;/code&gt; is &lt;code class=&quot;language-text&quot;&gt;3&lt;/code&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[&yet “Class of 2014”: David Dias, Lynn Fisher, Philipp Hancke, Julie Ann Horvath, Peter Saint-Andre]]></title><description><![CDATA[Today we’re honored to welcome a few new amazing individuals to the &yet team.Here at &yet, we strongly believe that each person who joins…]]></description><link>https://blog.andyet.com/2014/03/25/welcome-new-teammates/</link><guid isPermaLink="false">https://blog.andyet.com/2014/03/25/welcome-new-teammates/</guid><pubDate>Tue, 25 Mar 2014 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Today we’re honored to welcome a few new amazing individuals to the &amp;#x26;yet team.&lt;/p&gt;
&lt;p&gt;Here at &amp;#x26;yet, we strongly believe that each person who joins our team should fundamentally improve what it’s like to work here. We also count on our new teammates to help lead us toward being the type of company we want to see ourselves become. So you can bet that we take extra care and consideration when adding new folks to the team. &lt;/p&gt;
&lt;p&gt;Here’s a tiny (but brilliant) glimpse of the direction we’re heading, represented by the newest additions to &amp;#x26;yet team:&lt;/p&gt;
&lt;h3 id=&quot;david-dias&quot;&gt;&lt;a href=&quot;#david-dias&quot; aria-label=&quot;david dias permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;David Dias&lt;/h3&gt;
&lt;p&gt;Many of us came to know David &lt;a href=&quot;https://www.twitter.com/daviddias&quot;&gt;(@daviddias)&lt;/a&gt; through his role as organizer of the incredible &lt;a href=&quot;http://2013.lxjs.org/&quot;&gt;LXJS&lt;/a&gt;. We were lucky enough to have him provide some extra help pulling off the madness of RealtimeConf, too. We’ve been so deeply inspired by his enthusiasm and genuine positivity that we asked David to join the team. Considering his zeal for security and his knowledge of Node, David has taken on a central role in further developing and pushing forward the capabilities of &lt;a href=&quot;https://liftsecurity.io&quot;&gt;^Lift Security&lt;/a&gt; and the &lt;a href=&quot;http://nodesecurity.io&quot;&gt;Node Security Project&lt;/a&gt;, starting with the &lt;a href=&quot;https://ti.to/lift-security/node-sec-dev-portland&quot;&gt;training class happening this May in Portland&lt;/a&gt;. &lt;/p&gt;
&lt;h3 id=&quot;lynn-fisher&quot;&gt;&lt;a href=&quot;#lynn-fisher&quot; aria-label=&quot;lynn fisher permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Lynn Fisher&lt;/h3&gt;
&lt;p&gt;We’re grateful &lt;a href=&quot;https://andyet.com/team/luke&quot;&gt;Luke&lt;/a&gt; introduced us to his friend and fellow Arizonan Lynn Fisher &lt;a href=&quot;https://www.twitter.com/lynnandtonic&quot;&gt;(@lynnandtonic)&lt;/a&gt; about a year ago. We were immediately blown away by her &lt;a href=&quot;http://lynnandtonic.com/work/logical-doctor/&quot;&gt;artwork’s sense of humor&lt;/a&gt;, the expressiveness of her design, and the &lt;a href=&quot;http://thoughts.lynnandtonic.com/2013/10/22/good-better-best/&quot;&gt;versatility of her talent&lt;/a&gt;. Thankfully, several of us got to meet her in person, too, at last year’s CSSConf. We fell in love with her relaxed personality that seemed a perfect fit with her unique aesthetic and jaw-dropping talent as an illustrator. In the short time she’s been on the team she’s managed to astound us a few hundred times with her creativity. Plus, Lynn is just super cool.&lt;/p&gt;
&lt;h3 id=&quot;philipp-hancke&quot;&gt;&lt;a href=&quot;#philipp-hancke&quot; aria-label=&quot;philipp hancke permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Philipp Hancke&lt;/h3&gt;
&lt;p&gt;WebRTC developer Philipp (“Fippo”) Hancke has been a longtime associate/collaborator with members of our team in the thick of the XMPP world. He has pioneered making XMPP/Jingle &amp;#x3C;3 WebRTC, which has enormously contributed to &lt;a href=&quot;http://andyet.com/team/lance&quot;&gt;Lance&lt;/a&gt;’s work on &lt;a href=&quot;https://github.com/legastero/stanza.io&quot;&gt;Stanza.io&lt;/a&gt; (a JavaScript API for an XML-free XMPP interface) and &lt;a href=&quot;https://github.com/legastero/jingle.js&quot;&gt;Jingle.js&lt;/a&gt;. You might know Fippo from his role as &lt;a href=&quot;https://vimeo.com/77289728&quot;&gt;Hornsby Cornflower&lt;/a&gt; at last year’s RealtimeConf. (A name which he enjoyed enough to continue to tweet from as &lt;a href=&quot;https://www.twitter.com/hcornflower&quot;&gt;@hcornflower&lt;/a&gt;!) Fippo has already had a huge impact on our team’s WebRTC work, including &lt;a href=&quot;https://github.com/HenrikJoreteg/SimpleWebRTC&quot;&gt;SimpleWebRTC&lt;/a&gt; and &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt;, and we can’t wait to see what he builds next. &lt;/p&gt;
&lt;h3 id=&quot;julie-ann-horvath&quot;&gt;&lt;a href=&quot;#julie-ann-horvath&quot; aria-label=&quot;julie ann horvath permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Julie Ann Horvath&lt;/h3&gt;
&lt;p&gt;Like many of our new team members, we’ve been in talks with Julie about joining our team for a long time. (In her case, it’s been a year and a half!). Julie &lt;a href=&quot;https://www.twitter.com/nrrrdcore&quot;&gt;(@nrrrdcore)&lt;/a&gt; is a terrific designer, outstanding communicator, and a person of tremendous character who we’re proud to (finally!) be able to work with. We’ve been watching with awe what she’s accomplished with &lt;a href=&quot;http://passionprojects.github.com&quot;&gt;Passion Projects&lt;/a&gt; and several members of our team had a chance to attend the &lt;a href=&quot;https://github.com/blog/1781-free-public-speaking-workshop-for-women&quot;&gt;public speaking workshop&lt;/a&gt; she organized, which many who were present considered to be a revolutionary moment in empowering women as conference speakers in the tech community. &lt;/p&gt;
&lt;h3 id=&quot;peter-saint-andre&quot;&gt;&lt;a href=&quot;#peter-saint-andre&quot; aria-label=&quot;peter saint andre permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Peter Saint-Andre&lt;/h3&gt;
&lt;p&gt;We &lt;a href=&quot;https://blog.andyet.com/2014/01/30/welcome-peter-saint-andre&quot;&gt;previously introduced Peter as our new CTO&lt;/a&gt;. He rounds out this list of a group of remarkable team members we’ve been able to add this year. We have been thrilled with the leadership he’s provided thus far in pushing forward our WebRTC efforts, and in thinking through how the additional structure we’re adding to our team can be in service of our ethos rather than in opposition to it.&lt;/p&gt;
&lt;p&gt;Welcome David, Lynn, Philipp, Julie, and Peter!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=SmHeP9Sve48&quot;&gt;Good luck. We’re all counting on you.&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing JS for Teams, a training experience that’s the first of its kind]]></title><description><![CDATA[Are you frustrated over how much of your JavaScript code is dependent on too few members of your team?Our team was there too. Over time, we…]]></description><link>https://blog.andyet.com/2014/03/07/introducing-js-for-teams/</link><guid isPermaLink="false">https://blog.andyet.com/2014/03/07/introducing-js-for-teams/</guid><pubDate>Fri, 07 Mar 2014 09:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Are you frustrated over how much of your JavaScript code is dependent on too few members of your team?&lt;/p&gt;
&lt;p&gt;Our team was there too. Over time, we’ve built a set of practices that have helped our team and clients write complex but sane JavaScript apps without depending heavily on one or two people.&lt;/p&gt;
&lt;p&gt;Using approaches Henrik Joreteg and &amp;#x26;yet introduced in &lt;a href=&quot;http://humanjavascript.com/&quot;&gt;Human JavaScript&lt;/a&gt;, after &lt;strong&gt;just two days&lt;/strong&gt; you and your dev team will walk away with a practical, more sensible path to building JS apps. And your code base will look like it was written by one solid JS dev.&lt;/p&gt;
&lt;p&gt;Introducing &lt;a href=&quot;http://jsforteams.com&quot;&gt;JS for Teams&lt;/a&gt;, a clear and simple approach to building complex JS apps—but it’s a bit more interesting than that. &lt;/p&gt;
&lt;p&gt;JS for Teams will be an &lt;strong&gt;unforgettable experience&lt;/strong&gt; that brings to training the multisensory magic of our last conference, &lt;a href=&quot;http://2013.realtimeconf.com/&quot;&gt;RealtimeConf&lt;/a&gt;. (If you missed out, RealtimeConf was an immersive experience tech conference—incorporating &lt;a href=&quot;https://soundcloud.com/andyet/old-world-still-modulates&quot;&gt;music&lt;/a&gt;, &lt;a href=&quot;http://2013.realtimeconf.com/something-greater-than-artifice/&quot;&gt;storytelling&lt;/a&gt;, and &lt;a href=&quot;http://2013.realtimeconf.com/video/&quot;&gt;interactive theatre&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Training of this kind is very attentive and hands-on, so &lt;strong&gt;seats are limited&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;Be the first to &lt;a href=&quot;http://jsforteams.com&quot;&gt;get your team’s spot secured&lt;/a&gt; by &lt;a href=&quot;https://confirmsubscription.com/h/r/9BF79A7BBE2ACB4F&quot;&gt;signing up for the announcement list&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Pete Seeger: lessons learned from a hard link to the old world.]]></title><description><![CDATA[When I was 17, two things occurred which changed my life forever.My grandfather passed away and left me a book by John Lomax entitled…]]></description><link>https://blog.andyet.com/2014/02/26/Pete-Seeger-lessons-learned-from-a-hard-link-to-the-old-world/</link><guid isPermaLink="false">https://blog.andyet.com/2014/02/26/Pete-Seeger-lessons-learned-from-a-hard-link-to-the-old-world/</guid><pubDate>Wed, 26 Feb 2014 16:40:00 GMT</pubDate><content:encoded>&lt;p&gt;When I was 17, two things occurred which changed my life forever.&lt;/p&gt;
&lt;p&gt;My grandfather passed away and left me a book by John Lomax entitled, &lt;em&gt;&lt;a href=&quot;https://archive.org/details/cowboysongsother00lomarich&quot;&gt;Cowboy Songs&lt;/a&gt;&lt;/em&gt;, and I discovered Pete Seeger’s seminal &lt;a href=&quot;http://www.folkways.si.edu/pete-seeger/american-favorite-ballads-vols-1-5/folk/music/album/smithsonian&quot;&gt;“American Favorite Ballads”&lt;/a&gt; record series produced by Smithsonian Folkways. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e41cca0952e8e34295063cfe200fc92d/b4294/Pete_American-Cowboy_resize.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 600px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 91.3907284768212%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAASABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAQCAwH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/2gAMAwEAAhADEAAAAdeTUY10UE51kYDf/8QAGhABAQACAwAAAAAAAAAAAAAAAgEAAxAhMf/aAAgBAQABBQIoY7MPi1qoSySdDn//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAdEAACAQQDAAAAAAAAAAAAAAAAARESICEiMWGB/9oACAEBAAY/As1T0aJ+mSUjbm3/xAAbEAEAAgIDAAAAAAAAAAAAAAABABExQRAhUf/aAAgBAQABPyHBNHiKLgXSimP007GDaVtOtwATEZ//2gAMAwEAAgADAAAAEAgHwP/EABgRAAIDAAAAAAAAAAAAAAAAAAABEBFB/9oACAEDAQE/EEWbH//EABkRAAIDAQAAAAAAAAAAAAAAAAARARAhMf/aAAgBAgEBPxBYIjlf/8QAGxABAAMBAQEBAAAAAAAAAAAAAQARITFBUWH/2gAIAQEAAT8QBbHTQ5cfKIV42C+B0iniFBPD9gpYOIlz1Lm6v7NYHPSEGgn/2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;American Favorite Ballads, Cowboy Songs&quot;
        title=&quot;&quot;
        src=&quot;/static/e41cca0952e8e34295063cfe200fc92d/b4294/Pete_American-Cowboy_resize.jpg&quot;
        srcset=&quot;/static/e41cca0952e8e34295063cfe200fc92d/0a254/Pete_American-Cowboy_resize.jpg 151w,
/static/e41cca0952e8e34295063cfe200fc92d/c8fe0/Pete_American-Cowboy_resize.jpg 303w,
/static/e41cca0952e8e34295063cfe200fc92d/b4294/Pete_American-Cowboy_resize.jpg 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Growing up as a ranch-hand in Silver City, New Mexico, the “real” history of the American cowboy was always important to my grandfather, and &lt;em&gt;Cowboy Songs&lt;/em&gt; was one of the only genuinely untainted collections of that oral tradition with lyrical content that wasn’t screened or edited by its publishers to be “safe.” &lt;/p&gt;
&lt;p&gt;As a musician wanting to know more about my personal heritage in American folk music, I soon inevitably discovered the work of Pete Seeger. With access to his live and candid albums made for Folkways, and his early traditional hits with &lt;a href=&quot;http://www.allmusic.com/artist/the-weavers-mn0000586689&quot;&gt;The Weavers&lt;/a&gt;, these songs that had only existed on the pages of the folk anthologies I was reading actually came to life. &lt;/p&gt;
&lt;p&gt;With Seeger maintaining a simplicity, passion, and voice akin to a spirit of as if he sang out a traditional ballad on the day it was written, I began to internalize the fact that everything I had been taught about engaging, appreciating, learning from, and making music was derived through a very different system not much older than my grandfather. &lt;/p&gt;
&lt;p&gt;I began to see that great music didn’t have to be made by just coming up with “material” for live and recorded performances, but there was a much deeper root of common song that had been occurring naturally, and changing regionally as long as the human race has existed. &lt;/p&gt;
&lt;p&gt;This was music birthed out of need for sharing common ideas or struggles, popular or unpopular, disposed to the circumstances of the writer’s family, community, national identity, or lack thereof. &lt;/p&gt;
&lt;p&gt;The term “folk music” seemed like it had been culturally hijacked from me and interpreted for me as a commercial genre coupled to recordings based on the sound of a pretty acoustic guitar and a soft voice. &lt;/p&gt;
&lt;p&gt;Essentially what I saw through Pete was the not-so-long-dead antithesis of music made as a means of the expansion of personal fame and empire, being that he’d say “I feel that my whole life is a contribution,” not just a sound, feeling, or recorded product. &lt;/p&gt;
&lt;p&gt;Music could actually become a wonderful vehicle to bring people together and build the spirit and depth of their community—not only inspire the listening individual, as I had been so accustomed to. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/eab61a7ab5a0c22932807d63c09a1145/b4294/pete_letters_resize.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 600px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQDAf/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAABuzoyxvIDbEJ0V//EABwQAAMAAQUAAAAAAAAAAAAAAAABAhAREiExQf/aAAgBAQABBQIfblYpanJ7dbaP/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAGBAAAgMAAAAAAAAAAAAAAAAAARARIDH/2gAIAQEABj8CWCsBf//EABsQAAICAwEAAAAAAAAAAAAAAAABESExUWFx/9oACAEBAAE/IXiIKIMu5PBrhMTWiumMOoIMn//aAAwDAQACAAMAAAAQh+d9/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxA1Cn//xAAWEQADAAAAAAAAAAAAAAAAAAAAECH/2gAIAQIBAT8QK//EAB0QAQACAgIDAAAAAAAAAAAAAAEAESExQYFRYcH/2gAIAQEAAT8Q2rTHUNUyO14lmZ5JWXCmRxASWEI2vdk+TDpcphY8kGls/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Letters from Pete&quot;
        title=&quot;&quot;
        src=&quot;/static/eab61a7ab5a0c22932807d63c09a1145/b4294/pete_letters_resize.jpg&quot;
        srcset=&quot;/static/eab61a7ab5a0c22932807d63c09a1145/0a254/pete_letters_resize.jpg 151w,
/static/eab61a7ab5a0c22932807d63c09a1145/c8fe0/pete_letters_resize.jpg 303w,
/static/eab61a7ab5a0c22932807d63c09a1145/b4294/pete_letters_resize.jpg 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Becoming more familiar with Pete’s work, I initially assumed he had long passed on as his contemporaries &lt;a href=&quot;http://www.woodyguthrie.org/&quot;&gt;Woody Guthrie&lt;/a&gt;, &lt;a href=&quot;http://ciscohouston.com/lyrics/&quot;&gt;Cisco Houston&lt;/a&gt;, and &lt;a href=&quot;http://www.leadbelly.org/&quot;&gt;Lead Belly&lt;/a&gt; had done decades before. In discovering that he was very much alive and active, as one working musician to another, I quickly wrote him a letter with a head full of questions concerning direction on initiating community-oriented music in an entirely post-indigenous city.&lt;/p&gt;
&lt;p&gt;Not expecting anything in return, I was surprised to find a simple postcard in the mail with just a couple sentences of thanks and that he was “a lucky old guy to receive a letter like” mine. &lt;/p&gt;
&lt;p&gt;Maybe it was youthful ignorance of the fact that he was a busy man, but I wasn’t satisfied with a simple reply so I kept writing with similar questions, and the responses grew from a sentence or two to a couple paragraphs with each exchange. &lt;/p&gt;
&lt;p&gt;He continued to do his best to summarize solutions for my concerns with a couple nuggets of wisdom at a time, and a pointer to helpful individuals and resources. &lt;/p&gt;
&lt;p&gt;Eventually, I ended up receiving an invite to come out and join in the music at the annual Beacon Strawberry Festival near his home in upstate New York which Pete and his family had supported for years. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e450b024ef19c8d39b7c43a790c5e081/a34d8/pete-and-I_2008_resize.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 542px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 110.59602649006621%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAWABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMEAf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHbkQjrgwzCgP/EABsQAAIDAQEBAAAAAAAAAAAAAAECAAMRExIi/9oACAEBAAEFAr7PAut6OVSD7qXCxxp2cBbsjuZ//8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHhAAAgAGAwAAAAAAAAAAAAAAAAECEBEhMUESE3H/2gAIAQEABj8Cg64rbKaxJHJ6ZWxRYHYXh//EABoQAQEBAQEBAQAAAAAAAAAAAAERACFRoUH/2gAIAQEAAT8hVHEyAbgMBXNPzXQX5ieA+YXTeRit9J5pbyMhCVW3CQcg3//aAAwDAQACAAMAAAAQb/eC/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAHhABAQACAgMBAQAAAAAAAAAAAREAITFRQWHBkaH/2gAIAQEAAT8QCIj6g6r6vGORJ5Ckvvk/mHMEJpP3IydWvwGKBVAM4NYMmEt2cgDAxLHzMbgpUm81Pqp2l+5//9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Pete and Ben at Beacon Strawberry Festival&quot;
        title=&quot;&quot;
        src=&quot;/static/e450b024ef19c8d39b7c43a790c5e081/a34d8/pete-and-I_2008_resize.jpg&quot;
        srcset=&quot;/static/e450b024ef19c8d39b7c43a790c5e081/0a254/pete-and-I_2008_resize.jpg 151w,
/static/e450b024ef19c8d39b7c43a790c5e081/c8fe0/pete-and-I_2008_resize.jpg 303w,
/static/e450b024ef19c8d39b7c43a790c5e081/a34d8/pete-and-I_2008_resize.jpg 542w&quot;
        sizes=&quot;(max-width: 542px) 100vw, 542px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The indelible lessons I acquired in tracking his work from the time of our first correspondence, to spending a week of music and conversation with him and his family in Beacon, are thus:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The commercial industry does not have to define the way you do things. You have to define how to do what you know is best by changing the system you live in daily, a step (or song) at a time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you listen to any of Seeger’s live recordings, you won’t be able to go more than five seconds without realizing that most of what he’s trying to do is simply get people to sing together. &lt;/p&gt;
&lt;p&gt;If you listen just a little more, you begin to realize that he’s also effectively making historic tunes relevant to the environment he’s in. &lt;/p&gt;
&lt;p&gt;PBS aptly titled their 2008 biographical documentary, &lt;a href=&quot;http://www.pbs.org/wnet/americanmasters/episodes/pete-seeger/full-film-pete-seeger-the-power-of-song/2864/&quot;&gt;&lt;em&gt;The Power of Song&lt;/em&gt;&lt;/a&gt;, essentially encompassing the philosophy of his work. It could easily have been called “The Power of Pete,” or “The Power of Folk” or something individually focused, but it becomes relatively hard to interpret his work that way when he’d constantly quote individuals like Aunt Molly Jackson. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.folkways.si.edu/aunt-molly-jackson-and-john-greenway/the-songs-and-stories-of/american-folk-struggle-protest/music/album/smithsonian&quot;&gt;Jackson&lt;/a&gt; was a miner’s widow from Clay County, Kentucky whose songs written from her painfully home grown experience helped fuel the founding of the National Miner’s Union, making a clean break from living under the continually deadly circumstances their former employers had provided. &lt;/p&gt;
&lt;p&gt;Under his title chapter “What can a song do?” from his autobiography &lt;a href=&quot;http://www.goodreads.com/book/show/686463.The_Incompleat_Folksinger&quot;&gt;The Incompleat Folksinger&lt;/a&gt;, Pete recalled her passion about the matter, saying “Protest songs? Even the singer of dirty songs is protesting sanctimoniousness. … Propaganda or proper goose; the truth is what matters.” &lt;/p&gt;
&lt;p&gt;To someone living in the era before the commercialization of music, who’d seen common songs change the entire way of life for her community, the fact that songs have meaning and can actually do something (no matter what label they’re given) was as real as the fact that she could talk about it. The label must’ve seemed like an inconsequential stereotype of her passion for doing something good.&lt;/p&gt;
&lt;p&gt;Truly, recording technology is what changed music forever. &lt;/p&gt;
&lt;p&gt;By the time that Pete hit the pop-charts with The Weavers in 1950 with a song like &lt;a href=&quot;http://rd.io/x/QUYLDjd4heE/&quot;&gt;“Goodnight Irene,”&lt;/a&gt; the task he had taken before him was to broaden the spectrum of the topical song for the American public to know that they could engage with real, life-changing topics besides the only one that was safe (mostly) in all its various forms: love. &lt;/p&gt;
&lt;p&gt;As their follow-up best-seller, &lt;a href=&quot;http://rd.io/x/QUYLDjd4iis/&quot;&gt;“Tzena, Tzena”&lt;/a&gt; became another unlikely release during the American post-war era, bringing to light the fact that fantastic music and culture was happening around the world, not just in the very powerful USA. &lt;/p&gt;
&lt;p&gt;Pop-music by this time was on a fast train away from producing urban hymns that meant more to families and individuals than the one who performed them, building up an immensely viable market through the perfect image of crooning singers like Bing Crosby and Frank Sinatra. &lt;/p&gt;
&lt;p&gt;Yet what made the market even exist goes back to one point in history, the proliferation of the Victor Talking Machine Company’s “Victrola” record player. With it, two completely new doors opened for the public: the ability to listen to anything without having to go anywhere or engage anyone, and the ability to be sold ‘music’ as a commercial product in the form of a medium other than a human performing it directly. &lt;/p&gt;
&lt;p&gt;This literally marked the beginning of the end for the indigenous oral-traditions of the western world, drawing a hard line between the old and new era, and Pete knew it.&lt;/p&gt;
&lt;p&gt;When one comes to the conclusion that there’s something they can see that they feel others aren’t able to and should know about, they can do one of two things: get pridefully cynical about their “enlightenment,” building up unnecessary animosity for themself, or bring a helpful idea to the table in a relevantly relatable way so that the community can grow and learn from it. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/Pete_Weavers_edit_resize.jpg&quot; alt=&quot;Weavers 78rpm records, blacklisted Decca radio station copy&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“Don&apos;t Play,” followed by a radio station manager’s signature. A leftover from the Weaver’s blacklisting during the McCarthy era.&lt;/em&gt; &lt;/p&gt;
&lt;p&gt;Though not methodically compromising a core-conviction of enabling communities through bringing back their old songs and standardizing new ones, Pete chose to tie himself to the commercial industry knowing that there was something he could do: not to attempt to undermine it himself with useless rhetorical attacks, but to thoroughly organize with others like him to be a clear example of how much life can be found in the old alternative. &lt;/p&gt;
&lt;p&gt;The simplicity of getting people of all religions, creeds, and associations together in the same room singing something they all relate to and/or believe in could be much more exciting than a hall packed with faceless individuals quietly focused on a person-centric performance. &lt;/p&gt;
&lt;p&gt;Even when I met him, Pete hated having himself as a central focus, always redirecting conversations to the great work the community was doing together. &lt;/p&gt;
&lt;p&gt;A neighbor of his from Beacon told me, “The best way to get to know Pete is to work along side him doing something useful, like picking up trash.”&lt;/p&gt;
&lt;p&gt;No matter what form it took, contributing to something community-centric was his way of “turning over the temple tables” that be, if you will. &lt;/p&gt;
&lt;p&gt;As a younger man in an age where members versed in the way people’s music used to be grew old, Pete was able to maintain direct access to quite a few of America’s surviving known and unknown members of folk music history before recording existed—many of whose songs (or arrangements) made it into our national archives at the Library of Congress, and the priceless anthologies collected first hand by John and Alan Lomax, Carl Sandburg, and William Doerflinger, among others. &lt;/p&gt;
&lt;p&gt;This culture of preservation fell into two camps: publisher, and performer. You could read all you wanted to about the way songs used to be sung and what they meant, or you kept on where the songwriters left off by doing it yourself. &lt;/p&gt;
&lt;p&gt;Songsters like Woody Guthrie and Huddie “Lead Belly” Ledbetter became Pete’s counterparts in showing the world that folk music, in the truest sense of the word, was still very much alive and at work apart from the ever expanding recording industry. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/01e44b71955a6668b19a59f95149e437/b4294/Pete_woody-lead-belly_resize.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 600px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 77.48344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAZGpeahIH//EABsQAAMAAgMAAAAAAAAAAAAAAAECAxESISIj/9oACAEBAAEFAkHEpMSLLhD2FG0kPP8A/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHRAAAQMFAQAAAAAAAAAAAAAAAAESIRExQWGBwf/aAAgBAQAGPwKo7AkLyTY23oh//8QAGRAAAwEBAQAAAAAAAAAAAAAAAREhADHR/9oACAEBAAE/IU2tmESAXr1MQq+maxTHOXCtkC4AQ7Tv/9oADAMBAAIAAwAAABAnD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAQEAAgIDAAAAAAAAAAAAAAERACFRcTFB8f/aAAgBAQABPxAAhvURJm9WWpxZMfo2EIvTTl4UoFLt+4I4iK4L4X0ZLSI7HnP/2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Woody Guthrie and Lead Belly&quot;
        title=&quot;&quot;
        src=&quot;/static/01e44b71955a6668b19a59f95149e437/b4294/Pete_woody-lead-belly_resize.jpg&quot;
        srcset=&quot;/static/01e44b71955a6668b19a59f95149e437/0a254/Pete_woody-lead-belly_resize.jpg 151w,
/static/01e44b71955a6668b19a59f95149e437/c8fe0/Pete_woody-lead-belly_resize.jpg 303w,
/static/01e44b71955a6668b19a59f95149e437/b4294/Pete_woody-lead-belly_resize.jpg 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;From small town juke joints to Carnegie Hall they played for all audiences, turning performances into opportunities to get people singing together, and familiar with songs important to either their heritage or collective identity. &lt;/p&gt;
&lt;p&gt;With blazing a trail for others to think critically via music and personally do something for the growth of their local human experience, this legacy becomes a critical idea to wrestle with at some point for contemporary musicians of 2014, during our post culturally-homogenized, global era. &lt;/p&gt;
&lt;p&gt;In contrast, the results from our more popularly prominent school of music have facilitated patterns that appear to have benefitted not only a self-centric mentality, but have completely redesigned the conventions of music interaction on an individual and communal level. This is why…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Being a Rock-Star is bullshit. If your work doesn’t tackle the concerns of anyone more than yourself, it’s not worth your time. Building community isn’t glamorous, but the rewards are better than fame.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The creation of music as content for individual consumption is really only an entertainment ecosystem that has existed for arguably less than a century, resulting in an economy of hedonistic escapism, so far as to say: as long as the product has just enough broad-spectrum emotional familiarity, multitudes will buy it or be satisfied with it, as the bar for creativity and critical thought in music is continually lowered to what may be tolerable. &lt;/p&gt;
&lt;p&gt;With such great emotionalism produced at such a rapid rate, this makes way for individually-targeted ‘microwaved’ empathetic experiences without a much deeper purpose than to feel something, rather than encouraging communally involved ones with a common cause. &lt;/p&gt;
&lt;p&gt;This continually reoccurring process becomes naturally sustainable in the common exhibition of what I call the “headphone-lifestyle.” &lt;/p&gt;
&lt;p&gt;There is no greater self-contained experience than one only available to the body of a listening individual. If one is subjected to be familiar only with sound rather than an individual artist making music, they are destined to remove the human element from the sound’s creation and associate it with either an idea, emotion, or memory. &lt;/p&gt;
&lt;p&gt;Interaction with others becomes interaction with an extension of self, which can be beneficial with many other tools, yet is dangerous to the identity of music itself. &lt;/p&gt;
&lt;p&gt;Instead this curates a reversal of shared-interaction: when said individual buys a ticket to see a show from the band that they had been individually listening to, and either silently watches, or is lost in an excitedly loud myriad of people. &lt;/p&gt;
&lt;p&gt;Ultimately, this may show them that they are not as important as the ones exalted on the stage. It cannot only become an unhealthy manifestation of worshipping the idealization of what a rock-star is portrayed in image to be, but an intentional or unintentional dismissal of their worth in an associated “scene,” thus driving many to vie for acceptance within an imaginary demographic much “cooler” than the one they come from. &lt;/p&gt;
&lt;p&gt;To clarify, there is a tremendous difference between this model and making the inspiring creative work of talented groups and individuals available to everyone, but what can be challenged here is our popular recording industry’s facilitation of a fantastically cool image, creating an unachievable fantasy for the common individual to acquire, who then may vicariously live it out through the products and services the industry provides. &lt;/p&gt;
&lt;p&gt;If those products and services are accepted by a majority, then a purposed cultural-homogenization can be achieved. How did we get here? Circumstances and clever marketing.&lt;/p&gt;
&lt;p&gt;By the 1960s, recording methodology reached a creative apex in available technology and artist ingenuity that will never again be repeated in this way and has been only emulated since (whether by use or building of instrumentation). &lt;/p&gt;
&lt;p&gt;The market was ready to produce its Elvis, The Beatles, and Bob Dylan. Each of whom’s story is different, and whose musical contribution within the industry and to the public was huge, of course, but whose total glorification has left us generationally found wanting. &lt;/p&gt;
&lt;p&gt;It’s done two things.&lt;/p&gt;
&lt;p&gt;One, provided us with what I call Recursive Photocopy Theory (RPT), which is a core method of post-modern music crafting: with every proceeding generation of pop-musician copying and pasting past elements of earlier pop-music production for further use, the overall integrity of the end result becomes a degraded image of something before it. Just like a photocopy of a photocopy. &lt;/p&gt;
&lt;p&gt;And two, artists feel culturally pressured to build a viable personal image, more so even than to grow in compositional ability and discovery, to maintain a hopeful relevance in letting others continually think they’re a “big deal” within the forefront of current or new trends. &lt;/p&gt;
&lt;p&gt;This then perpetuates a “hit-it-big” mentality, eventually burning artists out by their late 20s when they never become commercially popular, yet the opportunity to do something communally relevant with their talents exists as long as they do. &lt;/p&gt;
&lt;p&gt;The ever increasing need for the alternative to be resurrected (ironically at Pete’s death) is now more important than ever, if not only to have an alternative to fitting into total cultural-homogeny. &lt;/p&gt;
&lt;p&gt;Pete really hit it right with his simple phrase he repeated to me and many others throughout the past few decades, “Think globally, act locally.” &lt;/p&gt;
&lt;p&gt;Building small, globally minded, intentional communities that are individually authentic, but equipped to interact with any other one around the world seems to far exceed a lack of resistance to assimilation into an esoteric monster of one globalized society, making way for some universal “elite.” &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/86721d72fa9707637d0c5d2b0cc7fcad/6f6fc/Pete_seeger_when_we_march_into_berlin_8d41980u.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 77.48344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHNmmMuD//EABgQAQADAQAAAAAAAAAAAAAAAAECICEx/9oACAEBAAEFAnuUUk//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAZEAEAAgMAAAAAAAAAAAAAAAAAATEQEXH/2gAIAQEABj8CxSerbf/EAB8QAQACAQMFAAAAAAAAAAAAAAEAEUEhMWGBkaGx8P/aAAgBAQABPyE0tN1fMEYO0v4RM8L3AFsoHEY2rpP/2gAMAwEAAgADAAAAEADP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAMBAQEBAAAAAAAAAAAAAQARITFBUfH/2gAIAQEAAT8Q0J+McsRQdADQHIXBA57CbrsB9P3NqgNNoMhZ4Y5P/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Pete in Army uniform surrounded by people singing, 1941&quot;
        title=&quot;&quot;
        src=&quot;/static/86721d72fa9707637d0c5d2b0cc7fcad/3cb18/Pete_seeger_when_we_march_into_berlin_8d41980u.jpg&quot;
        srcset=&quot;/static/86721d72fa9707637d0c5d2b0cc7fcad/0a254/Pete_seeger_when_we_march_into_berlin_8d41980u.jpg 151w,
/static/86721d72fa9707637d0c5d2b0cc7fcad/c8fe0/Pete_seeger_when_we_march_into_berlin_8d41980u.jpg 303w,
/static/86721d72fa9707637d0c5d2b0cc7fcad/3cb18/Pete_seeger_when_we_march_into_berlin_8d41980u.jpg 605w,
/static/86721d72fa9707637d0c5d2b0cc7fcad/6f6fc/Pete_seeger_when_we_march_into_berlin_8d41980u.jpg 617w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Pete was able to jump into the process of global music-commercialization during his time in this way, organically growing another path culturally and environmentally with the door to access it from the inside-out. His collective work was done only with the help of willing communities, small and large, across the US (and the world). &lt;/p&gt;
&lt;p&gt;This proves to be a reminder that: though wonderful to most of our senses, music itself isn’t as important as what you do with it. The artist has no idea of the repercussions of their work, but it’s very healthy to stay mindful that it can easily ripple a global influence, positive or negative. &lt;/p&gt;
&lt;p&gt;This draws us back to an attempt at making a solid definition about something generally believed to be utterly subjective. &lt;/p&gt;
&lt;p&gt;Pete said, “A good song reminds us of what we’re fighting for.” &lt;/p&gt;
&lt;p&gt;Tackling community issues in song is at the heart of traditional folk-music, and has become a relatively lost art, or has been generated from RPT so that it topically contains a deluge of emotional struggle with no physically or historically concrete subject matter. &lt;/p&gt;
&lt;p&gt;Those who make statements with their new or rearranged traditional lyricism are generally pushed to the fringes of relevant culture like languages that die. When English became the first language of the U.K., Welsh and its dialects were pushed to the edges of the islands, and now exist nearly entirely as a showpiece for historic reminiscence, sung at genre-specific events or recited in special-interest groups. &lt;/p&gt;
&lt;p&gt;It would be ludicrous to say that folk music is the only music that serves a legitimate purpose, as one can draw incredible inspiration from the unending variety of forms music composition itself has acquired at this point, but unless it’s profitable, our culturally-uniform music industry is pushing critical ideas and purposes out to the point of total sterilization. &lt;/p&gt;
&lt;p&gt;At the present time, our youth are either not aware of the power available to them in the methods behind making folk-music, or they seem to have to do their best to match up to producing something universally relevant by rooting themselves in trending commercial methods.&lt;/p&gt;
&lt;p&gt;What did Seeger think? Well, he’d say: “Participation – that’s what’s gonna save the human race.” &lt;/p&gt;
&lt;p&gt;No matter what you believe about that statement, I can’t forget about what stemmed from this belief in another thing he taught me: Never refuse an audience; always get them singing together no matter who they are. &lt;/p&gt;
&lt;p&gt;In Pete’s words, he said “I have sung in hobo jungles, and I have sung for the Rockefellers, and I am proud that I have never refused to sing for anybody.” &lt;/p&gt;
&lt;p&gt;With participation being one of the major themes of his work, he aptly summarized this entire concern to me in this way in one of our letters: “Sure young people are clobbered by the music business. But go to the kids in schools, in summer camps. Show ‘em what fun it is to join in. Later they’ll find out that songs helped us get rid of slavery, and work together!” &lt;/p&gt;
&lt;p&gt;Without even saying it outright, he was able to encapsulate the fact that if a song is simple enough to bring children together and help them learn something while enjoying it, the performer is well on their way to giving that generation a better start than to only be subject to the industry’s influences. &lt;/p&gt;
&lt;p&gt;In his autobiography, he also brought this up saying: “Singing with children in the schools has been the most rewarding experience of my life.” &lt;/p&gt;
&lt;p&gt;To continue in on the spirit of this, if we collectively focused less of our attention on national shock-value entertainment, and more on songs and stories of community identity, we could turn our music into something that actually equips, not distracts our youth.&lt;/p&gt;
&lt;p&gt;Singing to kids in school for free is nice, but how then is one supposed to make a living at music? You don’t—not directly. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3bce5cf1713bf55868d752fcd0389bd7/b4294/Pete_Children_resize.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 600px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 110.59602649006621%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAWABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAECAwT/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAfamMbwhOAloP//EABwQAAEFAAMAAAAAAAAAAAAAAAIAAQMRExIiMv/aAAgBAQABBQJgGsxUrMJX0Bzuf3st0Rc1/8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8BhD//xAAWEQADAAAAAAAAAAAAAAAAAAAAEBH/2gAIAQIBAT8BI//EABsQAQACAgMAAAAAAAAAAAAAAAAhoQExETKB/9oACAEBAAY/AsRbraGE6eNW1bl//8QAGhAAAwEBAQEAAAAAAAAAAAAAAAERITFBcf/aAAgBAQABPyH1CqjTAU1lSj4HsUJHP2PgWkl5UCcq1EyH/9oADAMBAAIAAwAAABBnF/8A/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAEDAQE/EDQuwuWIC//EABgRAQEBAQEAAAAAAAAAAAAAAAEAESFR/9oACAECAQE/EOeSNtZW/8QAHxABAAIBBAMBAAAAAAAAAAAAAQARITFxofBRgbHB/9oACAEBAAE/EEPZGrZxEgo+8KJQoW82xEiM54xL2ABMfiXbf6wzTothfEIXfvaNpvgu+6z/2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;American Folk Songs for Children Album&quot;
        title=&quot;&quot;
        src=&quot;/static/3bce5cf1713bf55868d752fcd0389bd7/b4294/Pete_Children_resize.jpg&quot;
        srcset=&quot;/static/3bce5cf1713bf55868d752fcd0389bd7/0a254/Pete_Children_resize.jpg 151w,
/static/3bce5cf1713bf55868d752fcd0389bd7/c8fe0/Pete_Children_resize.jpg 303w,
/static/3bce5cf1713bf55868d752fcd0389bd7/b4294/Pete_Children_resize.jpg 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Unless the opportunity clearly presents itself, living in an all-or-nothing mentality typically becomes a drain on the artist’s sanity, and the pockets of others they depend on unless they go to work to support themselves. Pete iterated this thought recalling he was told “that someone once asked &lt;a href=&quot;http://www.docsguitar.com/&quot;&gt;Doc Watson&lt;/a&gt; for advice on whether or not he should become a professional singer of folk songs. Doc was reported to have answered in his usual grave way: ‘Do it as a last resort, when you’ve failed in every other way to make a living.’” &lt;/p&gt;
&lt;p&gt;If you don’t know about Doc, the first thing to note is that being blind didn’t stop his commercial success which began in his 40s, and he was just as similarly interested in being an auto-mechanic as a musician. &lt;/p&gt;
&lt;p&gt;Similarly, music is not the only good thing in the world, and not everyone is naturally disposed to make it. The place of importance that music itself is often lifted to culturally can also cheat the progress of other important working talents that artists possess that can benefit the growth of their community. &lt;/p&gt;
&lt;p&gt;In Pete’s case, he quickly moved from organizing music performance and publication, to organizing political and environmental rallies, with one of his best known successful contributions being the effort to clean up the Hudson River, which had slowly become an industrial sewer that passed right by his home. In fact, the first conversation that he and I had in person was about water chestnuts that were native to the Hudson, and had begun to flourish again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The way things were, doesn’t have to be better than the way things are. Knowing the past well can really help you change the course of what you don’t like about where we’re headed.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The world has changed a bit since Pete and Doc were in their prime. &lt;/p&gt;
&lt;p&gt;How is it possible to maintain an honest approach to giving authentic folk-music in a new era that seems to have moved on entirely? &lt;/p&gt;
&lt;p&gt;Just as Pete and others thoroughly held integrity during an earlier iteration of the recording industry’s expansion, so can anyone of this age keep on before our cultural experience is almost entirely wrapped into endeavors that can change at an executive whim. &lt;/p&gt;
&lt;p&gt;Fear is the general enemy of doing anything, and if we aren’t afraid of the powers that be or the way others respond to doing something “real” with our time, we might actually be able to fulfill some goals that involve them. &lt;/p&gt;
&lt;p&gt;To say that the era of indigenous western music is over and that its methods have become irrelevant is a contemporarily logical thought, yet in essence is also the worst enemy of our oral tradition’s existence and survival. We are at the door to letting our story in music become either an optional parallel path, or one changed on the peak of a parabolic track. &lt;/p&gt;
&lt;p&gt;Using our tools to create experiences that draw others communally together rather than to build isolated, yet entertained lives is a great problem before us now. &lt;/p&gt;
&lt;p&gt;The general roots-informed approaches I’ve been witness to are polarized in either an attempt to mirror the exact recreation of folk musics of the early to mid-century modern eras, or produce work in a more polished singer-songwriter market which is viable to a commercial niche. &lt;/p&gt;
&lt;p&gt;Though wonderfully talented and enjoyable artists are making meaningful music in both ways, the separation between the identity of our cultural folk idiom and its ability to adapt and change to the induction of relevant digital tools and the community-building opportunities within the Internet holds the key to finally let it breathe beyond the attraction of what it once was in simpler times.&lt;/p&gt;
&lt;p&gt;To maintain natural growth and relevance, just as in the historic cultural evolution of the 20th century, our common expression must be willing to adopt new tools as desired, is necessary, and needed while fully utilizing the power of its traditional methods. &lt;/p&gt;
&lt;p&gt;Our tragedy happens when identity is defined by image, rather than image being a relatively unimportant byproduct of executing the method.&lt;/p&gt;
&lt;p&gt;Additionally, the means of execution are then wrapped up in a process of maintaining an image easily stereotyped to fit an existing commercial genre. Applicable influence to our growth can then be hindered by the fact that the tools we are using are so coupled to what others think we should look like, that exploring the use of new mediums in the folk idiom is met with grave opposition because folk music’s aesthetic is now forever cemented in time at it earliest interceptions of audio and film recording. &lt;/p&gt;
&lt;p&gt;The opportunity of global cultural integration and building strong communities in the Internet is not an enemy to folk music–the dehumanization and dissolution of its powerful components for market viability in advertising is. &lt;/p&gt;
&lt;p&gt;A second culture now parallels the importance of regional community expression: the global. &lt;/p&gt;
&lt;p&gt;Both are important, and neither of which deserve to be completely left behind for the other. Though not yet fully realized, vital tools are being further developed daily for making the possibility of advancement in indigenous collaboration available within the Internet. &lt;/p&gt;
&lt;p&gt;Direct browser-to-browser audio interfacing (WebRTC), and new possibilities of in-browser sound generation through audio-specific programming interfaces (web-audio APIs), among other tools, are pushing the roof off of constraints previously known against realtime collaborative music projects. &lt;/p&gt;
&lt;p&gt;What I foresee being immediately necessary as a next step into our universally-accessible paradigm of common folk expression is the iterated development of an organic ecosystem that takes the form of an application with a gravely simple interface. In simpler terms: the GitHub method applied to collaborative music making. &lt;/p&gt;
&lt;p&gt;It could be an in-browser digital audio workstation that allows for the open sourcing or private working of current recording projects, with an ability to browse and collaborate on any project listed as open, or available to take its current form and make something else with it by request to the original author. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7588589b01899aa2c39c67e9811da7c6/b4294/Pete_Audacity-Screenshot_edit.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 600px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 44.370860927152314%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwT/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAddclqAw/8QAGhAAAgIDAAAAAAAAAAAAAAAAAQMAAhETIP/aAAgBAQABBQI3tnYyBjOP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFREBAQAAAAAAAAAAAAAAAAAAABL/2gAIAQIBAT8BpT//xAAYEAACAwAAAAAAAAAAAAAAAAAAMQEgIf/aAAgBAQAGPwLJGOn/xAAbEAABBAMAAAAAAAAAAAAAAAABABFBkSAhMf/aAAgBAQABPyF+4RoIulioKSVDD//aAAwDAQACAAMAAAAQH/8A/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8QiP/EABgRAAIDAAAAAAAAAAAAAAAAAAABEUFx/9oACAECAQE/EFCkYR//xAAdEAABAwUBAAAAAAAAAAAAAAABABFhECExQVGh/9oACAEBAAE/EBX8j4JlYMHtzRAOxWC//9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Audacity Screeshot&quot;
        title=&quot;&quot;
        src=&quot;/static/7588589b01899aa2c39c67e9811da7c6/b4294/Pete_Audacity-Screenshot_edit.jpg&quot;
        srcset=&quot;/static/7588589b01899aa2c39c67e9811da7c6/0a254/Pete_Audacity-Screenshot_edit.jpg 151w,
/static/7588589b01899aa2c39c67e9811da7c6/c8fe0/Pete_Audacity-Screenshot_edit.jpg 303w,
/static/7588589b01899aa2c39c67e9811da7c6/b4294/Pete_Audacity-Screenshot_edit.jpg 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Crucially simple UI example: Audacity. I&apos;ve successfully taught this software in condensed form to multiple classes of gradeschoolers.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It could also take the form of demultiplexing various instrument and voice inputs from around the world, adjusted for latency via distance by physical location, and sent as one audio output for internationally live performances in one or many physical locations. The lack of available synthesized instruments and sound generation there within would only be as limited as our time and creativity in making them. &lt;/p&gt;
&lt;p&gt;As constraints are continually lifted, and further problems are solved, the possibilities in collaboration and creation are only as limited as our imagination. &lt;/p&gt;
&lt;p&gt;I feel the repercussions of making incredibly simple tools like this easily available to everyone would have the possibility of bridging many socio-economic gaps in music making which have been previously unchangeable. &lt;/p&gt;
&lt;p&gt;In the voice of Pete, “Any darn fool can make something complex; it takes a genius to make something simple.” This will only work if it’s simple enough, and not sacrificed to the current gods of advertising.&lt;/p&gt;
&lt;p&gt;While introducing the old spiritual “You Gotta Walk That Lonesome Valley” at a Carnegie Hall concert with Arlo Guthrie in the mid 70s, Pete summarized the reality of ingenuity in folk music by repeating Woody Guthrie’s take on the matter: “One of the most important things which Woody taught me and a lot of others is that: you can make a combination between the best of the old and the new. It doesn’t have to be either one or the other, you can mix ‘em up!” &lt;/p&gt;
&lt;p&gt;I would dare to say that this sentiment can be applied not only to communally forged lyricism and balladry, but to the mediums and methods of our shared expression in this era and beyond. As the web enables accessible community-oriented environments, and what once was musical hardware is continually fully emulated in the browser, the accessibility of creative interaction is as simple as having access to a computer with a modern browser installed, and the Internet. &lt;/p&gt;
&lt;p&gt;I cannot say that this approach applies to indigenous communities outside of commercialized Western civilization who do not need it, but the creation within could lead to a new renaissance of tools, interaction, and the sound of our common song itself. This of course will look very different than regional old-world music, but the path is clearing to move forward in working within what we have rather than only by what we’ve seen in old films and recordings of the last century, taking much needed influence from those before us, but using their lessons to empower the critical growth of where we’re headed. &lt;/p&gt;
&lt;p&gt;Dealing with similarly expansive changes in his time, Pete dealt with the tension of the artist staying traditionally informed, yet still inventive and good at what they do by relating this idea to one of his greatest influences, Lead Belly: “Nowadays when the artist becomes a virtuoso, there is a greater tendency to cease being ‘folk.’” &lt;/p&gt;
&lt;p&gt;“When Lead Belly rearranged a folk melody he had come across—he often did—he did it in line with his own great folk traditions.” Pete draws the line here for us between the words “folk” and “authentic.” As we look to what can be done in the contemporary, holding fast to the understanding of where our authentic identity came from and what it is now, could in our own way, enable us to “turn the clock back to when people lived in small villages and took care of each other.” &lt;/p&gt;
&lt;p&gt;The spirit of this truly has the chance to thrive in our physical and inter-networked world, or even within a collision of both. It’s become much easier to sacrifice our time and efforts doing something self-indulgent, but sacrificing our lives in building authentic community will continue to make our story one that grows into something greater than commercial artifice.&lt;/p&gt;
&lt;p&gt;The recent passing of Pete Seeger concludes the swan song of an era in the American oral tradition that now almost entirely exists only in our written and recorded archives dedicated to such things. &lt;/p&gt;
&lt;p&gt;We’re now physically left without that link to the way things were, and missing a direct conversation as to why people did such great things in a long line of their oral traditions and folk expressions. &lt;/p&gt;
&lt;p&gt;Still, with the prolific gift of Pete’s body of work along with others like him, we’ve been given the great opportunity to preserve, foster, and build what the community music of our indigenous culture will look like in the era to come. &lt;/p&gt;
&lt;p&gt;This doesn’t have to stop with the death of a folk champion, let’s do something together with our craft that matters now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.andyet.com/uploads/Pete_Seeger_1984_resize.jpg&quot; alt=&quot;Pete Seeger, 1984&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Tao of Ops: What exactly is a DDoS?]]></title><description><![CDATA[As more and more people are enjoying the Internet as part of their every day lives, so too are they experiencing its negative aspects. One…]]></description><link>https://blog.andyet.com/2014/02/24/what-exactly-is-a-ddos/</link><guid isPermaLink="false">https://blog.andyet.com/2014/02/24/what-exactly-is-a-ddos/</guid><pubDate>Mon, 24 Feb 2014 16:42:00 GMT</pubDate><content:encoded>&lt;p&gt;As more and more people are enjoying the Internet as part of their every day lives, so too are they experiencing its negative aspects. One such aspect is that sometimes the web site you are trying to reach is not accessible. While sites can be out of reach for many reasons, recently one of the more obscure causes has moved out of the shadows: The Denial of Service attack. This type of attack is also known as a DoS attack. It also has a bigger sibling, the Distributed Denial of Service attack.&lt;/p&gt;
&lt;p&gt;Why these attacks are able to take web sites offline is right there in their name, since they deny you access to a web site. But how they cause web sites to become unavailable varies and quickly gets into more technical aspects of how the Internet works. My goal is to help describe what happens during these attacks and to identify and clarify key aspects of the problem.&lt;/p&gt;
&lt;p&gt;First we need to define some terms:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A Web Site&lt;/strong&gt; --
When you open your browser and type in (or click on) a link, that link tells the browser how to locate and interact with a web site. A link is made up of a number of pieces along with the site address. Other parts include how to talk to the computers that provide that service and also what type of interaction you want with the web site. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Web Address, aka the Uniform Resource Locator&lt;/strong&gt; --
A link, to be geeky for a moment, is what is known as a Uniform Resource Locator (URL). Although most people think of a URL as &quot;how web sites are addressed,&quot; it is actually a part of a much wider method of access to any service on the Internet. That said, the vast majority URLs provide a way to navigate web sites.&lt;/p&gt;
&lt;p&gt;This link, &lt;a href=&quot;https://en.wikipedia.org/wiki/Url&quot;&gt;https://en.wikipedia.org/wiki/Url&lt;/a&gt; contains the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;https://&lt;/code&gt; The browser needs to talk to the web site using the https scheme - a secure web browsing web request&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;en.wikipedia.org&lt;/code&gt; The address of the computer (or computers) that will provide the information and content of the web site&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;/wiki/Url&lt;/code&gt; The resource you want to get from the web site&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The address portion of a link, the &quot;en.wikipedia.org&quot; part above, is itself made up of various parts known as the Top Level Domain (TLD) and the hostname. For our example the TLD is &quot;.org&quot; and the hostname is &quot;en.wikipedia&quot; - the two pieces are then used by the browser to make a query to the Domain Name System (DNS). This request takes the name, determines which Name Server is the authority for that name, and then returns an IP address for the name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IP Address&lt;/strong&gt; --
Each computer that is connected to the Internet is given a unique address so it can be identified and contacted. This unique Internet Protocol (IP) address allows clients (such as web browsers) and other computers to find and access it. Once your browser retrieves the IP address for a web site it can then begin to contact a computer using the appropriate protocol style to get the contents of the web site and display it for you.&lt;/p&gt;
&lt;p&gt;Now that&apos;s a lot of little things all happening behind the scenes when you go visit a web site :) - but now that we know what we&apos;re working with, it will make describing what a DoS is easier.&lt;/p&gt;
&lt;p&gt;When someone launches a Denial of Service attack they are trying to make the computers providing a service unable to perform their duties. The difference between a DoS and a DDoS is in how many outside computers are helping perform the attack. A Distributed Denial of Service attack is, as the name implies, distributed across many many computers, all of which are making requests to the target over and over again.&lt;/p&gt;
&lt;p&gt;That is the crux of a DoS - one group of computers overload another group of computers by making the target have to process so many requests it cannot keep up. Let&apos;s work through two examples of what a DoS attack would look like in the real world:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 1&lt;/strong&gt; --
Think of the Internet as a highway and your browser is trying to access it via the on-ramp. While a small stream of cars is trying to get onto the highway things go well, but when the flow of cars gets to be too many all hell breaks loose and everyone comes to a halt and sits in traffic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example 2&lt;/strong&gt; --
During home games, Denver Broncos quarterback Peyton Manning is able to call plays out to his team. The players can hear him just fine, since hometown crowds are quiet during the plays. However, once the Broncos traveled to the Super Bowl to take on the Seattle Seahawks, things changed. The Seattle fans, known for being very loud, were able to act as a &quot;12th man&quot; of the Seattle defense. So much so that Manning&apos;s teammates could not hear him above the noise of the Seattle fans! They were suffering from a Distributed Denial of Service attack from more than one fan at a time.&lt;/p&gt;
&lt;p&gt;As with any attack, you immediately begin to wonder how they can be prevented from happening and how to deal with them while they are active. This answer varies, not only because of the nature of each attack, but also because there are quite a few different kinds of DoS attacks. This little essay is getting rather long already so we might discuss counter-measures in a future blog post.&lt;/p&gt;
&lt;p&gt;However, now when your browser is giving you an error message or the &quot;spinner&quot; is doing its best to annoy you, you will at least have the information to understand what is happening when the IT or Support people say &quot;Yes, we are being DDoS&apos;d.&quot;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Eran Hammer introduces Hapi 2.0]]></title><description><![CDATA[Last week, Eran Hammer came to the &yet office to introduce Hapi 2.0.Hapi is a very powerful and highly modular web framework created by…]]></description><link>https://blog.andyet.com/2014/02/03/eran-hammer-introduces-hapi-2/</link><guid isPermaLink="false">https://blog.andyet.com/2014/02/03/eran-hammer-introduces-hapi-2/</guid><pubDate>Mon, 03 Feb 2014 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Last week, &lt;a href=&quot;http://twitter.com/eranhammer&quot;&gt;Eran Hammer&lt;/a&gt; came to the &amp;#x26;yet office to introduce Hapi 2.0.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://hapijs.com&quot;&gt;Hapi&lt;/a&gt; is a very powerful and highly modular web framework created by Eran and his team at Walmart Labs. It currently powers the mobile walmart.com site, as well as some portions of the desktop site.  With that kind of traffic, you could definitely say Hapi is battle-tested.&lt;/p&gt;
&lt;p&gt;Hapi&apos;s quickly becoming a popular framework among Node developers. Since mid-2013, &amp;#x26;yet has been using Hapi for all new projects and we&apos;ve begun porting several old projects to use it, too.&lt;/p&gt;
&lt;p&gt;Before he started his presentation, Eran casually mentioned that he planned to at least touch on every feature in Hapi, and boy did he succeed.&lt;/p&gt;
&lt;p&gt;From creating your server and adding routes and their handlers, to writing and utilizing plugins, and even configuring some options to help your Ops team keep your application running smoothly, everything is covered. As he talks about features, Eran also points out each breaking change along the way to facilitate updating your applications from Hapi 1.&lt;/p&gt;
&lt;p&gt;If you&apos;re currently using Hapi, are considering using it in the future, or are even a little bit curious about it, I highly recommend watching.&lt;/p&gt;
&lt;iframe src=&quot;//player.vimeo.com/video/85799484&quot; width=&quot;500&quot; height=&quot;281&quot; frameborder=&quot;0&quot; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&amp;[yet presents Eran Hammer on Hapi 2.0](http://vimeo.com/85799484) from &amp;[yet](http://vimeo.com/andyet) on [Vimeo](http://vimeo.com).</content:encoded></item><item><title><![CDATA[Welcome Peter Saint-Andre]]></title><description><![CDATA[It's an honor to introduce Peter Saint-Andre as a new member of our team and as the CTO of &yet.Peter has a long history of leadership in…]]></description><link>https://blog.andyet.com/2014/01/30/welcome-peter-saint-andre/</link><guid isPermaLink="false">https://blog.andyet.com/2014/01/30/welcome-peter-saint-andre/</guid><pubDate>Thu, 30 Jan 2014 09:45:00 GMT</pubDate><content:encoded>&lt;p&gt;It&apos;s an honor to introduce Peter Saint-Andre as a new member of our team and as the CTO of &amp;#x26;yet.&lt;/p&gt;
&lt;p&gt;Peter has a long history of leadership in Internet standards as an IETF Area Director, Executive Director of the XMPP Standards Foundation, and his involvement in standardizing technologies like WebSockets and OAuth. He&apos;s among a handful of people who&apos;ve (with quite little fanfare) helped pave the Information Superhighway™.&lt;/p&gt;
&lt;p&gt;His experience and involvement with Internet security, distributed systems, and collaboration is a boon to our team as well. &lt;/p&gt;
&lt;p&gt;Peter&apos;s one of the original members of the Jabber, Inc. team who created the most widely distributed protocol for realtime communication (XMPP). He&apos;s given over a decade of deep consideration to the ways people use technology to collaborate and has a personal passion for making that better.&lt;/p&gt;
&lt;p&gt;Peter has an incredible ability to digest complexity and produce clarity. He persistently works to build consensus among teams and effectively communicate deeply technical subjects.&lt;/p&gt;
&lt;p&gt;As our CTO, Peter will help us use the knowledge and creations of our team to solve important, interesting problems for our customers and the open source community.&lt;/p&gt;
&lt;p&gt;But we didn&apos;t merely recruit Peter because of his technical aptitude and accomplishments. Many of our team members have worked with Peter in the XMPP community and have experienced a level of patient, unselfish servant leadership that has long been an inspiration to our entire team. He is an outstanding listener, thoughtful, and endlessly positive.&lt;/p&gt;
&lt;p&gt;As Bear, our most seasoned developer, puts it: &quot;I want to be Peter when I grow up.&quot; And Bear isn&apos;t alone in that sentiment.&lt;/p&gt;
&lt;p&gt;We believe Peter is the best possible choice to help lead our team of leaders and help us continue to forge a distributed team that is increasingly reflective of our values of what an organization should be.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The web has outgrown the browser (a web-lover's web-loving rant).]]></title><description><![CDATA[It used to all make sense.The web was once nothing but documents. Just like you'd want some type of file browser UI to dig through files on…]]></description><link>https://blog.andyet.com/2014/01/17/web-has-outgrown-the-browser/</link><guid isPermaLink="false">https://blog.andyet.com/2014/01/17/web-has-outgrown-the-browser/</guid><pubDate>Fri, 17 Jan 2014 13:30:00 GMT</pubDate><content:encoded>&lt;p&gt;It used to all make sense.&lt;/p&gt;
&lt;p&gt;The web was once nothing but documents. &lt;/p&gt;
&lt;p&gt;Just like you&apos;d want some type of file browser UI to dig through files on your operating system, obviously, you need some type of document browser to view all these web-addressable &quot;documents&quot;. &lt;/p&gt;
&lt;p&gt;But over time, those &quot;documents&quot; have become a lot more. A. lot. more. &lt;/p&gt;
&lt;p&gt;But I can now use one of these &quot;documents&quot; to have a 4 person video/audio conference on &lt;a href=&quot;https://talky.io&quot;&gt;Talky&lt;/a&gt; with people anywhere in the world, play incredible full-screen first-person shooters at 60fps, write code in a full-fledged editor, or {{ the reader may insert any number of amazing web apps here }} using nothing but this &quot;document viewer&quot;.&lt;/p&gt;
&lt;p&gt;Does calling them &quot;documents&quot; seem ridiculous to anyone else? Of course it does. Calling them &quot;sites&quot; is pretty silly too, actually because a &quot;site&quot; implies a document with links and a URL. &lt;/p&gt;
&lt;p&gt;I know the &quot;app&quot; vs. &quot;site&quot; debate is tired and worn. &lt;/p&gt;
&lt;p&gt;Save for public, content-heavy sites, &lt;em&gt;all&lt;/em&gt; of the apps that I&apos;m asked to write by clients these days at &amp;#x26;yet are fully client-side rendered.&lt;/p&gt;
&lt;p&gt;The browser is not an HTML renderer for me, it&apos;s the world&apos;s most ubiquitous, yet capable, &lt;em&gt;runtime&lt;/em&gt;. With the amazing capabilities of the modern web platform, it&apos;s to the point where referring to a browser as a document viewer is a insult to the engineers who built it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is a fundamental difference when you treat the browser as a runtime instead of a document renderer&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;I typically send it nothing but a doctype, a script tag, and a stylesheet with permanent cache headers.  HTML just happens to be the way I tell the browser to &lt;em&gt;download my app&lt;/em&gt;. I deal with the initial latency issues by all-but-ensuring visitors hit the app with a primed cache. This is pretty easy for apps that are opened frequently or are behind a static login page in which you prefetch the app resources. With proper cache headers the browser won&apos;t even do the 304 not-modified dance. It will simply start executing code.&lt;/p&gt;
&lt;p&gt;This makes some people cringe, and many web purists (luddites?! #burn) would argue that everything should gracefully degrade and that there isn&apos;t, or at least there shouldn&apos;t be, &lt;em&gt;any&lt;/em&gt; distinction between a JavaScript app and site. When I went to EdgeConf in NYC the &quot;progressive enhancement&quot; panel said a lot of things like &quot;your app should still be usable without JS enabled&quot;. Often &quot;javascript is disabled&quot; is really the time when the browser is downloading your javascript. To this I say:&lt;/p&gt;
&lt;p&gt;WELL, THEN SHOW ME A TALKY.IO CLONE THAT GRACEFULLY DEGRADES!&lt;/p&gt;
&lt;p&gt;It simply &lt;em&gt;cannot&lt;/em&gt; be done. Like it or not, the web has moved on from that myopic view of it. The blanket graceful degradation view of the web no longer makes sense when you can now build apps whose &lt;em&gt;core&lt;/em&gt; use case is fully dependent on a robust JavaScript runtime.&lt;/p&gt;
&lt;p&gt;I had a great time at Chrome Dev Summit, but again, the core message of the &quot;Instant Mobile Apps&quot; talk was: &quot;render your html on the server to avoid having your render blocking code require downloading your JS before it can start executing.&quot;&lt;/p&gt;
&lt;p&gt;For simple content-driven sites, I agree. Completely. The demo in that particular talk was the Chrome developer documentation. But it&apos;s a ridiculously easy choice to render documentation server side. (In fact the notion that there was ever a client-side rendered version to begin with was surprising to me.)&lt;/p&gt;
&lt;p&gt;If your view of the web lacks a distinction between clientside apps and sites/documents, I&apos;d go as far as to say that you&apos;re now part of the problem.&lt;/p&gt;
&lt;p&gt;Why? &lt;/p&gt;
&lt;p&gt;Because that view enables corporate IT departments to argue for running old browsers without getting laughed out of the building.&lt;/p&gt;
&lt;p&gt;Because that view keeps some decision makers from adopting 100% JavaScript apps and instead spending money on native apps with web connectivity. &lt;/p&gt;
&lt;p&gt;Because that view wastes precious developer time inventing and promoting hacks and workarounds for shitty browsers when they could be building next-generation apps. &lt;/p&gt;
&lt;p&gt;Because that view enables you to argue that your proficiency of browser CSS hacks for IE7 is still relevant. &lt;/p&gt;
&lt;p&gt;Because that view will &lt;em&gt;always&lt;/em&gt; keep the web locked into the browser.&lt;/p&gt;
&lt;h2 id=&quot;what-about-offline&quot;&gt;&lt;a href=&quot;#what-about-offline&quot; aria-label=&quot;what about offline permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about offline?&lt;/h2&gt;
&lt;p&gt;I&apos;m writing this on a plane without wifi and of course, using a native app to do so. There are two primary reasons for this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The offline web is still crap. See &lt;a href=&quot;http://offlinefirst.org/&quot;&gt;offlinefirst.org&lt;/a&gt; and &lt;a href=&quot;http://blog.hood.ie/2013/11/say-hello-to-offline-first/&quot;&gt;this hood.ie post&lt;/a&gt; for more.&lt;/li&gt;
&lt;li&gt;All my favorite web-based tools are still stuck in the browser.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The majority of users will &lt;em&gt;never ever&lt;/em&gt; open a browser without an Internet connection, type in a URL and expect ANYTHING to happen.&lt;/p&gt;
&lt;p&gt;Don&apos;t get me wrong, I&apos;m &lt;em&gt;very&lt;/em&gt; supportive of the offline first efforts and they are crucial for justifying that &lt;/p&gt;
&lt;p&gt;We have a very different view of apps that exist &lt;em&gt;outside&lt;/em&gt; of the browser. In fact, the expectation is often reversed: &quot;Oh right, I &lt;em&gt;do&lt;/em&gt; need a connection for this to work&quot;.&lt;/p&gt;
&lt;p&gt;Chrome OS is one approach, but I think its 100% cloud-based approach is more hardcore than the world is ready to adopt and certainly is never going to fly with the indie data crowd or the otherwise Google-averse. &lt;/p&gt;
&lt;p&gt;So, have I ranted enough yet?&lt;/p&gt;
&lt;p&gt;According to Jake Archibald from Google, &lt;a href=&quot;https://github.com/slightlyoff/ServiceWorker/#serviceworker-design&quot;&gt;ServiceWorkers&lt;/a&gt; will land in Canary sometime early 2014. This work is going to &lt;em&gt;fundamentally&lt;/em&gt; change what the web can do. &lt;/p&gt;
&lt;p&gt;If you&apos;re unfamiliar with ServiceWorkers (previously called Navigation Controllers), they let you write your own cache control layer in javascript for your web application. ServiceWorkers promise to serve the purpose that appcache was intended for: truly offline web apps. &lt;/p&gt;
&lt;p&gt;At a high level, they now let javascript developers building clientside apps to treat the existence of a network connection as an &lt;em&gt;enhancement&lt;/em&gt; rather than an expectation. &lt;/p&gt;
&lt;p&gt;You may think, &quot;Oh, well, the reason we use the web is because access to the network provides our core value as an app.&quot;&lt;/p&gt;
&lt;p&gt;While I&apos;d tend to agree that most of the useful apps fundamentally require data from the internet to be truly useful, you&apos;re missing the point. &lt;/p&gt;
&lt;p&gt;Even if the value of your app depends entirely on a network connection, you can now intercept requests and choose to answer them from caches that you control, while in parallel attempting to fetch newer versions of those resources from the network.&lt;/p&gt;
&lt;p&gt;If you think about it, that capability is no different than something like Facebook for iOS or Android. &lt;/p&gt;
&lt;p&gt;That Facebook app&apos;s core value is unquestioningly derived from seeing your friends&apos; latest updates and photos, which you&apos;re obviously not going to get without a connection. But the fundamental difference is this: the native app will still open the app and show you all the cached content it has. As a result (and for other reasons) the OS has given those types of apps a privileged status.&lt;/p&gt;
&lt;p&gt;With full programmatic cache control for the web that ServiceWorkers will offer, you&apos;ll be able to choose to load your app and whatever latest content you had downloaded &lt;em&gt;from cache first&lt;/em&gt; while optionally trying to connect and download new things from the network. The addition of a controllable cache layer in web apps means that an app like facebook really has no compelling reason to be a native app. I mean, really. If you break it down, that app is mostly a friend timeline browser, right? (the key word there being &lt;em&gt;browser&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;BUT, even with the addition of ServiceWorkers, there&apos;s another &lt;em&gt;extremely&lt;/em&gt; important difference: user perception.&lt;/p&gt;
&lt;p&gt;We&apos;ve spent years teaching users that things they use in their web browser simply do not work offline. Users understand (at least at on some unconscious level) that the browser is the native app that gets sites/documents from the Internet. From a user experience standpoint, trying to teach the average user anything different is attempting to roll a quarry full of rocks up a hill.&lt;/p&gt;
&lt;p&gt;This is where it starts to become apparent that failing to draw a distinction between a fully client &quot;apps&quot; and a website really starts to become a disservice to all these new capabilities of the web platform. It doesn&apos;t matter how good the web stack becomes, it will &lt;em&gt;never&lt;/em&gt; compete with native apps in the &quot;native&quot; space while it stays stuck in the browser.&lt;/p&gt;
&lt;p&gt;The addition of &quot;packaged&quot; chrome apps is an admirable, but in my opinion, still inadequate attempt at addressing this issue. &lt;/p&gt;
&lt;p&gt;At the point where a user on a mobile device opts to &quot;add to home screen&quot; the intent from the user is more than just a damn bookmark, they&apos;re saying: &quot;I want access to this on the same level as my native apps&quot;. It&apos;s a &lt;em&gt;user&apos;s request for an installation of that app&lt;/em&gt;, but in reality it&apos;s treated as a shitty, half-assed install that&apos;s really just a bookmark. But the intent from the user is clear: &quot;I want a special level of quick and easy access to this specific &lt;em&gt;app&lt;/em&gt;&quot;. &lt;/p&gt;
&lt;p&gt;So why not just embrace that what they&apos;re actually trying to do is &quot;install&quot; that web application into their operating system? &lt;/p&gt;
&lt;p&gt;Apple sort of does this for Mac Apps. After you first &quot;sideload&quot; (a.k.a. download from the web and try to run) a native Mac desktop app, they treat it a bit like an awkward stepchild when you first open it. They warn you and tell you: hey, this was an app downloaded from the Internet, are you sure you want to let this thing run?&lt;/p&gt;
&lt;p&gt;While I&apos;m not a fan of the language or the FUD involved with that, the timing makes perfect sense to me. At the point I&apos;ve opted to &quot;install&quot; something to my homescreen on my mobile device (or the equivalent to that for desktop), that seems like the proper inflection point to verify with the user that they do, in fact, want to let this app have access to specific &quot;privileged&quot; OS APIs. &lt;/p&gt;
&lt;p&gt;Without a simple way to install and authorize a clientside web app, these kinds of apps will always get stuck in the uncanny valley of half-assed, semi-installed apps. &lt;/p&gt;
&lt;p&gt;So why bother in the first place? Why not just do native whenever you want to build an &quot;app&quot;? Beyond providing a way to build for multiple platforms, there&apos;s one more thing the web has that native apps don&apos;t have: a URL.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;UNIFORM&lt;/em&gt; RESOURCE LOCATOR concept is easy to take for granted, but it&apos;s extremely useful to be able to reference things like links to emails inside gmail, or a tweet, or a very specific portion of documentation. Being able to naturally link between apps on the web is what gives the web its power. It&apos;s unfortunate that many, when they first start building single page applications don&apos;t update URLs as they go and fail to &lt;a href=&quot;http://www.kendoui.com/blogs/teamblog/posts/14-01-07/please-respect-the-back-button.aspx&quot;&gt;respect the &quot;back&quot; button&lt;/a&gt;, thus breaking the web. &lt;/p&gt;
&lt;p&gt;But when done properly, the blending the rich interactivity of native apps with the addressability and ubiquity of the web is a thing of beauty.&lt;/p&gt;
&lt;p&gt;I cannot understate how excited I am about Service Workers. Because finally, we&apos;ll have the ability to build web applications that treat network resources the same way that good native applications do: as an enhancement.&lt;/p&gt;
&lt;p&gt;Of course, the big &lt;em&gt;IF&lt;/em&gt; is whether platforms play along and actually treat these types of apps as first class citizens. &lt;/p&gt;
&lt;p&gt;Call me an optimist, but I think the capabilities that ServiceWorkers promise us, will shine a light on the bizarre awkwardness of the concept of opening a browser to access offline apps. &lt;/p&gt;
&lt;p&gt;The web platform&apos;s capabilities have outgrown the browser.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Let&apos;s help the web to make its next big push.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;I&apos;m &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; on twitter. I&apos;d love to hear your thoughts on this.&lt;/p&gt;
&lt;p&gt;For further reading on ServiceWorkers, here is &lt;a href=&quot;https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md&quot;&gt;a great explainer doc&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also, check out &lt;a href=&quot;http://humanjavascript.com&quot;&gt;my book on building sanely structured single page applications&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Silo-Free WebRTC at VUC]]></title><description><![CDATA[One of the most talked about presentations at RealtimeConf 2013 was yeti Lance Stout and Philipp Hancke's demonstration of WebRTC signaling…]]></description><link>https://blog.andyet.com/2013/12/13/silo-free-webrtc-at-vuc/</link><guid isPermaLink="false">https://blog.andyet.com/2013/12/13/silo-free-webrtc-at-vuc/</guid><pubDate>Fri, 13 Dec 2013 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the most talked about presentations at &lt;a href=&quot;https://vimeo.com/77289728&quot;&gt;RealtimeConf 2013&lt;/a&gt; was yeti &lt;a href=&quot;https://twitter.com/lancestout&quot;&gt;Lance Stout&lt;/a&gt; and &lt;a href=&quot;https://github.com/fippo&quot;&gt;Philipp Hancke&apos;s&lt;/a&gt; demonstration of WebRTC signaling over XMPP, resulting in a federated video call within the browser. &lt;/p&gt;
&lt;p&gt;This demo caught the attention of &lt;a href=&quot;http://www.voipusersconference.org/&quot;&gt;The VoIP Users Conference, or VUC&lt;/a&gt; a weekly, live discussion about all the telephony things, which began in 2007. Lance and Philipp will be joining the VUC community on December 27 at noon (Eastern Time) to discuss the potential of WebRTC as an interoperable tool to communicate within established protocols. &lt;/p&gt;
&lt;p&gt;Philipp and Lance have been working together for some time on projects (&lt;a href=&quot;https://github.com/fippo/strophe.jingle&quot;&gt;strophe.jingle&lt;/a&gt; and &lt;a href=&quot;https://github.com/legastero/stanza.io&quot;&gt;Stanza.io&lt;/a&gt;, respectively) that push forward the ability of developers to utilize XMPP in tandem with the web, specifically WebRTC.&lt;/p&gt;
&lt;p&gt;Join their conversation two weeks from today on Friday, December 27, at the &lt;a href=&quot;http://www.voipusersconference.org/&quot;&gt;VoIPUsersConference.org&lt;/a&gt;, or track it on their &lt;a href=&quot;https://plus.google.com/u/0/communities/114149566116254233716&quot;&gt;Google+&lt;/a&gt; community.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Happy Thanksgiving! Supporting our community, npm, and open source developers]]></title><description><![CDATA[At &yet, we give Thanksgiving bonuses. The tradition has become something outward-focused.Software developers hold an exceptionally…]]></description><link>https://blog.andyet.com/2013/11/27/happy-thanksgiving/</link><guid isPermaLink="false">https://blog.andyet.com/2013/11/27/happy-thanksgiving/</guid><pubDate>Wed, 27 Nov 2013 10:50:00 GMT</pubDate><content:encoded>&lt;p&gt;At &amp;#x26;yet, we give Thanksgiving bonuses. The tradition has become something outward-focused.&lt;/p&gt;
&lt;p&gt;Software developers hold an exceptionally privileged place in society. We feel not guilty, but grateful for this—yet we fervently believe to whom much has been given, much is required.&lt;/p&gt;
&lt;p&gt;Last year, the thrust of our Thanksgiving bonus was providing each of our team one day of paid time off per month to donate to making the world a better place, with us matching any gifts toward that organization.&lt;/p&gt;
&lt;p&gt;This year, we have several Thanksgiving announcements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We are continuing our program from last year of paid time off for volunteering and financial matching of accompanying donations.&lt;/li&gt;
&lt;li&gt;We are launching a new site to make our space and resources available to our community.&lt;/li&gt;
&lt;li&gt;We are making significant, ongoing financial support for open source projects via Adamantium Sponsorship of &lt;a href=&quot;https://scalenpm.org/&quot;&gt;scalenpm.org&lt;/a&gt; and allowing our developers to allocate GitTip.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&apos;s talk about the new stuff:&lt;/p&gt;
&lt;h3 id=&quot;communityandyetcom&quot;&gt;&lt;a href=&quot;#communityandyetcom&quot; aria-label=&quot;communityandyetcom permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a href=&quot;http://community.andyet.com&quot;&gt;community.andyet.com&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We are today launching the first rev of a project which we hope to use to help us better share the beautiful office space and resources we feel so privileged to have with our local community.&lt;/p&gt;
&lt;p&gt;We built many of the elements of the office we love with the aim being to share them and make them available to our community, but we haven&apos;t had a formal way to do that. This site is our first simple attempt to make that more possible.&lt;/p&gt;
&lt;h3 id=&quot;significant-ongoing-financial-support-for-open-source-projects-and-developers&quot;&gt;&lt;a href=&quot;#significant-ongoing-financial-support-for-open-source-projects-and-developers&quot; aria-label=&quot;significant ongoing financial support for open source projects and developers permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Significant, ongoing financial support for open source projects and developers&lt;/h3&gt;
&lt;p&gt;We know that there are many thankless jobs in open source which ultimately are the hidden costs that enable all of us who work with these technologies able to do the work we love and to ultimately pay our salaries.&lt;/p&gt;
&lt;p&gt;Building things sustainably is something we value and want to encourage everywhere we can.&lt;/p&gt;
&lt;p&gt;We want to see more support for open source projects by the businesses that depend on them, but rather than write blog posts and tweets about what people ought to do, we&apos;re going to help lead the only way we know how—by doing something. &lt;/p&gt;
&lt;p&gt;Specifically...&lt;/p&gt;
&lt;h3 id=&quot;1-adamantium-sponsorship-of-scalenpmorg&quot;&gt;&lt;a href=&quot;#1-adamantium-sponsorship-of-scalenpmorg&quot; aria-label=&quot;1 adamantium sponsorship of scalenpmorg permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Adamantium sponsorship of &lt;a href=&quot;https://scalenpm.org/&quot;&gt;Scalenpm.org&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have decided to have &amp;#x26;yet and ^Lift become &quot;Adamantium&quot; sponsors of scalenpm.org (and not just because Adam Brault and Adam Baldwin are the respective leads of those teams!) &lt;/p&gt;
&lt;p&gt;At this point, npm is a service we rely on as much, or more, as GitHub. And it costs real money to run on real servers. &lt;/p&gt;
&lt;h3 id=&quot;2-gittip-budgets-for-yet-developers&quot;&gt;&lt;a href=&quot;#2-gittip-budgets-for-yet-developers&quot; aria-label=&quot;2 gittip budgets for yet developers permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. &lt;a href=&quot;https://www.gittip.com/&quot;&gt;GitTip&lt;/a&gt; budgets for &amp;#x26;yet developers&lt;/h3&gt;
&lt;p&gt;Each developer on our team is getting $50 per week to target towards open source projects they support. We&apos;re pooling our donations as a team so that other companies are also encouraged to step up. &lt;/p&gt;
&lt;p&gt;Based on current numbers, doing this will make our team the largest weekly donor on GitTip. This is both awesome and sad. Seriously, we&apos;re not that big—it shouldn&apos;t even be financially possible for us to be the largest!&lt;/p&gt;
&lt;p&gt;(Big hat tip to our friends at &lt;a href=&quot;http://lincolnloop.com&quot;&gt;Lincoln Loop&lt;/a&gt; for already doing this, too. Though they don&apos;t pool their donations, so this awesome thing they&apos;re doing isn&apos;t visible to companies.)&lt;/p&gt;
&lt;p&gt;We hope GitTip becomes an arms race of who can best support open source developers for their contributions. We love the mission and the philosophy behind it and we hope that GitTip experiences npm-level explosive growth in this next year.&lt;/p&gt;
&lt;h3 id=&quot;3-team-sponsorship-of-substack--browserify&quot;&gt;&lt;a href=&quot;#3-team-sponsorship-of-substack--browserify&quot; aria-label=&quot;3 team sponsorship of substack  browserify permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. Team sponsorship of &lt;a href=&quot;http://github.com/substack&quot;&gt;Substack&lt;/a&gt; / &lt;a href=&quot;http://browserify.org/&quot;&gt;Browserify&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We rely on Substack&apos;s work in every app we build—most notably &lt;a href=&quot;https://github.com/substack/node-browserify&quot;&gt;Browserify&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;We have decided to target $1000 a month as a team specifically in sponsorship of his work.&lt;/p&gt;
&lt;h3 id=&quot;happy-thanksgiving&quot;&gt;&lt;a href=&quot;#happy-thanksgiving&quot; aria-label=&quot;happy thanksgiving permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Happy Thanksgiving!&lt;/h3&gt;
&lt;p&gt;We hope you and your loved ones have a Happy Thanksgiving from the &amp;#x26;yet team. &lt;/p&gt;
&lt;p&gt;Thank you so much to all our fellow teammates, clients, customers, sponsors, supporters, encouragers, friends and family. &lt;/p&gt;
&lt;p&gt;Everything we love about what we get to do would be impossible without you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Yetis take on the Node Summit]]></title><description><![CDATA[Next week, yetis Adam Baldwin and Luke Karrys will be traveling to San Francisco to speak at the second Node Summit, December 3-4. Node…]]></description><link>https://blog.andyet.com/2013/11/25/yetis-take-on-node-summit/</link><guid isPermaLink="false">https://blog.andyet.com/2013/11/25/yetis-take-on-node-summit/</guid><pubDate>Mon, 25 Nov 2013 14:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Next week, yetis &lt;a href=&quot;https://www.twitter.com/adam_baldwin&quot;&gt;Adam Baldwin&lt;/a&gt; and &lt;a href=&quot;https://www.twitter.com/lukekarrys&quot;&gt;Luke Karrys&lt;/a&gt; will be traveling to San Francisco to speak at the second &lt;a href=&quot;http://nodesummit.com/&quot;&gt;Node Summit&lt;/a&gt;, December 3-4. Node Summit brings together developers, leaders, and other technologists to discuss Node.js and its role in the future of the web and computing.&lt;/p&gt;
&lt;p&gt;Adam will be there representing both &lt;a href=&quot;http://liftsecurity.io/&quot;&gt;^Lift Security&lt;/a&gt;, and &lt;a href=&quot;https://nodesecurity.io/&quot;&gt;The Node Security Project&lt;/a&gt;, an ambitious open-source project he founded with the goal of auditing every single module in npm. Adam will be discussing Node.js security with Bert Belder of StrongLoop, Charlie Robbins of Nodejitsu, and Daniel Shaw of The Node Firm.&lt;/p&gt;
&lt;p&gt;Luke will be speaking during &lt;a href=&quot;http://nodesummit.com/nodetalks/&quot;&gt;NodeTalks&lt;/a&gt; on client solutions with Glenn Scott, of the Creative Artists Agency (CAA), and they&apos;ll discuss the challenges they faced on a recent project involving two different development teams coming together for the creation and deployment of a production node app and API to Microsoft Azure.&lt;/p&gt;
&lt;p&gt;The Node Security Project is also a sponsor of Node Summit, so if you&apos;re interested in attending, use the discount code SPEAKERFNF to get a 25% discount to the event, and while you&apos;re there swing by NSP&apos;s booth and grab a sticker. Tickets are available at &lt;a href=&quot;http://nodesummit.com/registration/&quot;&gt;NodeSummit.com&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Only those who are willing to take the risk of writing code that’s not perfect ever write code.]]></title><description><![CDATA[I’m gonna wax philosophic for a moment.I’m sure you’ve heard the joke that the code you wrote six months ago is always terrible code. It’s a…]]></description><link>https://blog.andyet.com/2013/11/19/only-those-who-risk-write-code/</link><guid isPermaLink="false">https://blog.andyet.com/2013/11/19/only-those-who-risk-write-code/</guid><pubDate>Tue, 19 Nov 2013 11:08:18 GMT</pubDate><content:encoded>&lt;p&gt;I’m gonna wax philosophic for a moment.&lt;/p&gt;
&lt;p&gt;I’m sure you’ve heard the joke that the code you wrote six months ago is always terrible code. It’s a feeling we all share I’m sure.&lt;/p&gt;
&lt;p&gt;Here&apos;s the thing: It’s not totally true, and the reason it&apos;s not true is &lt;em&gt;choice&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;When you are writing software you are perpetually making choices. Now, choice is a funny thing because we as humans cannot know the future. We are bound in time. The consequences of our choices are closed to us, as well or ill-informed as we happen to be it doesn’t matter. &lt;/p&gt;
&lt;p&gt;Every choice carries with it the potential for good or bad. That’s what a choice is. The part most of us forget though is that good and bad are stupid binary terms that have nothing to do with real life. &lt;/p&gt;
&lt;p&gt;You write the code, you make the choice in the Moment of Now. That your code could potentially be a ‘good’ or ‘bad’ decision at the same time is a bit of a paradox, but you have to find the middle of it. Find the eye of that hurricane of decisions, because the alternative is perpetual endless planning and inaction. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only those who are willing to take the risk of writing code that’s not perfect ever write code.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And your code is never perfect. That’s the nature of it. &lt;/p&gt;
&lt;p&gt;So: never doubt or apologize for the code you wrote in the past. And all code you’ve written is in the past, even the code you just finished writing just now. &lt;/p&gt;
&lt;p&gt;Accept that you made the choice and you can always make it again when you look at the code tomorrow with more information.&lt;/p&gt;
&lt;p&gt;One of the hardest things is when someone else finds a better way to do something that you already did. You just can’t forget that they had the benefit of YOU making the choice. They’re just operating in the aftermath.&lt;/p&gt;
&lt;p&gt;You’re never allowed to doubt yourself again is what I’m saying. Or you &lt;em&gt;are&lt;/em&gt;, but you &lt;em&gt;simultaneously&lt;/em&gt; have to have confidence in yourself. &lt;/p&gt;
&lt;p&gt;As one of my favorite authors (Stephen R Donaldson) says, you have to do both and ride the &quot;eye of the paradox&quot;.&lt;/p&gt;
&lt;p&gt;I&apos;ll leave you with a quote from Donaldson about the necessity of freedom:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;… are you a person—with volition and maybe some stubbornness and at least the capacity if not the actual determination to do something surprising—or are you a tool? A tool just serves its user. It’s only as good as the skill of its user, and it’s not good for anything else. So if you want to accomplish something special—something more than you can do for yourself—you can’t use a tool. You have to use a person and hope the surprises will work in your favor. You have to use something that’s free to not be what you had in mind.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;--Thomas Covenant (in Stephen R Donaldson&apos;s &lt;em&gt;The One Tree&lt;/em&gt;)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Why won't &yet put on another RealtimeConf?]]></title><description><![CDATA[This year's RealtimeConf was the most complex and ambitious thing I've ever been part of. At final count, we had 400 people involved in the…]]></description><link>https://blog.andyet.com/2013/11/12/why-wont-we-put-on-another-realtimeconf/</link><guid isPermaLink="false">https://blog.andyet.com/2013/11/12/why-wont-we-put-on-another-realtimeconf/</guid><pubDate>Tue, 12 Nov 2013 15:06:00 GMT</pubDate><content:encoded>&lt;p&gt;This year&apos;s &lt;a href=&quot;http://2013.realtimeconf.com&quot;&gt;RealtimeConf&lt;/a&gt; was the most complex and ambitious thing I&apos;ve ever been part of. At final count, we had 400 people involved in the making of the event. (What&apos;s quite humorous is we had 200 attendees, and 100 of those included among the contributors.)&lt;/p&gt;
&lt;p&gt;Taking into account our staff expenses, we &quot;only&quot; lost $230,000 putting on RealtimeConf. We had several members of our team focused mostly full-time on the event for over six months. If our team worked for free, we would have still lost around $50,000. (Incidentally, we are very grateful to our very generous &quot;tip jar&quot; contributors.)&lt;/p&gt;
&lt;p&gt;The assumption most people have made (and most certainly will make based on the above) is that we&apos;ve decided not to reprise the conference because we overextended ourselves and lost too much money.&lt;/p&gt;
&lt;p&gt;Yes, it was a &lt;em&gt;ton&lt;/em&gt; of work—but the large ensemble involved truly loved doing it and I believe the vast majority would gladly do it again. Now, it was a bit of an intense time for me because I&apos;d also committed to speaking at JSConf EU and LxJS in the month prior to the conference. But the amazing work of Mel, Amy, Mike, Jenn, Kathryn, Ben, and the rest of our team made that possible.&lt;/p&gt;
&lt;p&gt;And we knew we had made investments that weren&apos;t possibly sustainable by ticket sales or sponsorship and we pushed ahead regardless because we knew we could. (Let me be really clear: we are painfully lucky to be able to absorb this kind of loss and we know it. There have been times—even in our recent past—that wouldn&apos;t have been a possibility.)&lt;/p&gt;
&lt;p&gt;So, no—it wasn&apos;t the massive amount of energy and money we poured into the event which informed the decision to not do another RealtimeConf.&lt;/p&gt;
&lt;p&gt;To understand why we wouldn&apos;t reprise the event, let&apos;s talk about why we put on the conference.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In 2011 we had two original purposes in mind in creating the conference:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;WebSocket was just coming on the scene and we wanted to get together people who were building and experimenting with things on top of this new transport.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More importantly, we wanted to help bring together our friends in the XMPP and web dev communities and positively influence the direction of each with that exposure. &lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As far as the first is concerned, we attended a lot of conferences in 2013 and &lt;em&gt;all&lt;/em&gt; of the web development events had WebSocket-focused content. Realtime apps are still a newer area of web app development, but they&apos;re no longer a green field.&lt;/p&gt;
&lt;p&gt;And regarding the second: in the first two years of the conference we felt those connections and discussions happening, but with little fruit. This past year, that&apos;s finally happened in dramatic fashion, thanks largely to WebRTC. The XMPP community is more focused on the web than perhaps at any point in the technology&apos;s history, and the tooling for web is dramatically better as a result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thus, as far as &amp;#x26;yet is concerned, we have served our purpose, and we&apos;re ready to move on to different challenges.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In hindsight, this is a pattern we&apos;ve followed for years: We&apos;ve gained some experience and even recognition in an area, and rather than capitalizing on that for maximum financial gain or because it would be easier, we&apos;ve used it to empower the next step we could take to best leverage our position for greater gain. &lt;/p&gt;
&lt;p&gt;We feel compelled to use our position to be beneficial to the web and our local communities, but to do so patiently, without overextending our reach in the process.&lt;/p&gt;
&lt;p&gt;There&apos;s no investor hammering on us to make ridiculous profits—having &quot;enough&quot; is good enough for us. Most months, &amp;#x26;yet breaks even and we&apos;re happy with that.&lt;/p&gt;
&lt;p&gt;And so, sometimes, we decide to move on to taking the next small step.&lt;/p&gt;
&lt;p&gt;We are fond of vague ideas—things that have just gut feelings for a compass.  It feels right now like the future path is clear for the RealtimeConf community and we&apos;d like to move on to blurrier ground.&lt;/p&gt;
&lt;p&gt;One notion that&apos;s bound up in this decision as well—and one strongly alluded to throughout the conference narrative—is that we believe there&apos;s something greater than software, engineering, design, the web, etc.&lt;/p&gt;
&lt;p&gt;RealtimeConf is a pretty hardcore technology-focused conference. We have always had a thread of &quot;let&apos;s look at the big picture&quot; throughout the conference (especially the last two years) but nevertheless, it&apos;s a tech-minded event for tech-minded people.&lt;/p&gt;
&lt;p&gt;As we&apos;ve said in the past, &lt;strong&gt;we believe the web is not for web developers.&lt;/strong&gt; It&apos;s for everyone.&lt;/p&gt;
&lt;p&gt;We&apos;ve identified three areas of focus that we want to strongly push towards in the wake and spirit of what we&apos;ve been able to do with RealtimeConf.&lt;/p&gt;
&lt;h3 id=&quot;1-education&quot;&gt;&lt;a href=&quot;#1-education&quot; aria-label=&quot;1 education permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;1. Education&lt;/h3&gt;
&lt;p&gt;We want to bring experience and engagement to technology education. We are beginning to craft an education experience that will ultimately look like a mashup of RealtimeConf, &lt;a href=&quot;http://humanjavascript.com&quot;&gt;Human JavaScript&lt;/a&gt;, and a few new elements.&lt;/p&gt;
&lt;h3 id=&quot;2-indie-web--indie-data--indie-com&quot;&gt;&lt;a href=&quot;#2-indie-web--indie-data--indie-com&quot; aria-label=&quot;2 indie web  indie data  indie com permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;2. Indie Web / Indie Data / &quot;Indie Com&quot;&lt;/h3&gt;
&lt;p&gt;We want to continue to create and improve tools, open source software, and experiences that empower the average person to be part of the indie web movement, to own their own data, and to enjoy unsiloed communication. We are really just getting started with this, as far as we&apos;re concerned.&lt;/p&gt;
&lt;h3 id=&quot;3-a-new-event&quot;&gt;&lt;a href=&quot;#3-a-new-event&quot; aria-label=&quot;3 a new event permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;3. A new event&lt;/h3&gt;
&lt;p&gt;At this point, as far as indie web, indie data, and indie com are concerned, RealtimeConf was quite effectively preaching to the choir. In the spirit of our belief that the web is not for web developers, we&apos;d like to take that message and experience to a broader audience—but we believe in taking incremental steps rather than trying to eat the whole world in one bite. &lt;/p&gt;
&lt;p&gt;We aren&apos;t revealing anything just yet, but expect a future event aimed at a broader audience—&lt;strong&gt;something greater than RealtimeConf&lt;/strong&gt;. ;)&lt;/p&gt;
&lt;p&gt;If you want to be kept in the loop on what we&apos;re doing with these, &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;follow us on Twitter&lt;/a&gt; or &lt;a href=&quot;http://j.mp/andyet-news&quot;&gt;join our &amp;#x26;yet newsletter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We appreciate your help spreading the word.&lt;/strong&gt; We&apos;d love to hear your own thoughts via a good old-fashioned blog post!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[And Bang and Intercom security news]]></title><description><![CDATA[And Bang uses a service called Intercom for support communication and notifications. We were recently notified that Intercom was affected by…]]></description><link>https://blog.andyet.com/2013/11/07/and-bang-and-intercom-security-update/</link><guid isPermaLink="false">https://blog.andyet.com/2013/11/07/and-bang-and-intercom-security-update/</guid><pubDate>Thu, 07 Nov 2013 15:06:00 GMT</pubDate><content:encoded>&lt;p&gt;And Bang uses a service called Intercom for support communication and notifications. We were recently notified that Intercom was affected by a security breach of one of their database providers, MongoHQ. For the sake of transparency, we want to pass the information along to our users.&lt;/p&gt;
&lt;p&gt;Intercom found that 1 out of the 30 databases on MongoHQ had been accessed and states:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&quot;The data we store on MongoHQ is limited. The user records are not labeled with the customer name, product name, or domain name of the app with which they are associated. We don&apos;t store Intercom account information, passwords, billing information, or any Intercom messages or conversations, on MongoHQ.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;More detail on the breach is provided by &lt;a href=&quot;http://updates.intercom.io/&quot;&gt;Intercom&lt;/a&gt; on their website. &lt;/p&gt;
&lt;p&gt;We feel confident that Intercom handled the breach well and is taking appropriate action. The analysis of the breach provided by Intercom gives us confidence that And Bang user support data is in good hands.&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet we take security very seriously and we want to take this opportunity to remind you that we will never ask you for, nor want you to send to us your password, confidential information, or links to things that may include confidential information.&lt;/p&gt;
&lt;p&gt;If you ever have a security concern about And Bang please email us at &lt;a href=&quot;mailto:security@andbang.com&quot;&gt;security@andbang.com&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Henrik Joreteg on The Web Ahead]]></title><description><![CDATA[Today, yeti Henrik Joreteg, will be discussing WebRTC on the weekly podcast, The Web Ahead. The hour long show allows host Jen Simmons the…]]></description><link>https://blog.andyet.com/2013/10/31/henrik-on-the-web-ahead/</link><guid isPermaLink="false">https://blog.andyet.com/2013/10/31/henrik-on-the-web-ahead/</guid><pubDate>Thu, 31 Oct 2013 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;Today, yeti &lt;a href=&quot;https://www.twitter.com/henrikjoreteg&quot;&gt;Henrik Joreteg&lt;/a&gt;, will be discussing WebRTC on the weekly podcast, &lt;a href=&quot;http://5by5.tv/webahead&quot;&gt;The Web Ahead&lt;/a&gt;. The hour long show allows host &lt;a href=&quot;https://www.twitter.com/jensimmons&quot;&gt;Jen Simmons&lt;/a&gt; the opportunity to chat one on one with each week&apos;s guest on the burgeoning technologies and platforms that are pushing the web forward.&lt;/p&gt;
&lt;p&gt;Henrik is author of the popular library, &lt;a href=&quot;https://github.com/HenrikJoreteg/SimpleWebRTC&quot;&gt;SimpleWebRTC&lt;/a&gt; and lead developer for &lt;a href=&quot;https://talky.io/&quot;&gt;Talky&lt;/a&gt;, a tool we built for simple video chat and screen sharing. He&apos;s also heading up the effort to push WebRTC forward at &lt;a href=&quot;http://iswebrtcreadyyet.com/&quot;&gt;IsWebRTCReadyYet.com.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Henrik first spoke on WebRTC at &lt;a href=&quot;https://speakerdeck.com/henrikjoreteg/webrtc-jsconf-brazil-2013&quot;&gt;JSConf Brazil&lt;/a&gt; and built AT&amp;#x26;T&apos;s WebRTC focused &lt;a href=&quot;https://js.att.io/&quot;&gt;att.js&lt;/a&gt;, which was showcased by AT&amp;#x26;T at &lt;a href=&quot;https://blog.andyet.com/2013/jan/15/att-webrtc-and-yet-at-ces/&quot;&gt;CES&lt;/a&gt; earlier this year. He spoke recently about WebRTC, first on a Realtime Data panel at &lt;a href=&quot;http://edgeconf.com/2013-nyc/&quot;&gt;EdgeConf&lt;/a&gt; this past September, and again at &lt;a href=&quot;https://vimeo.com/77289728&quot;&gt;RealtimeConf 2013&lt;/a&gt;, in Portland a few weeks ago. Henrik will also be speaking at &lt;a href=&quot;http://2013.cascadiajs.com/&quot;&gt;Cascadia.js&lt;/a&gt; later this month.&lt;/p&gt;
&lt;p&gt;Go to &lt;a href=&quot;http://5by5.tv/webahead&quot;&gt;5by5&apos;s website&lt;/a&gt; to hear today&apos;s podcast with Henrik and Jen. &lt;/p&gt;
&lt;p&gt;&lt;em&gt;Edit:&lt;/em&gt; You can hear this podcast (Episode 59) by visiting &lt;a href=&quot;http://5by5.tv/webahead/59&quot;&gt;The Web Ahead&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[XSF elections evidence of web-friendly trend]]></title><description><![CDATA[We made the RealtimeConf, in large part, to bring the Web and XMPP communities together.
This year, we've seen huge strides in these two…]]></description><link>https://blog.andyet.com/2013/10/29/xsf-elections-web-friendly-trend/</link><guid isPermaLink="false">https://blog.andyet.com/2013/10/29/xsf-elections-web-friendly-trend/</guid><pubDate>Tue, 29 Oct 2013 15:30:00 GMT</pubDate><content:encoded>&lt;p&gt;We made the RealtimeConf, in large part, to bring the Web and XMPP communities together.
This year, we&apos;ve seen huge strides in these two communities coming together.
Most recently &lt;a href=&quot;http://wiki.xmpp.org/web/Lance_Stout_for_Council_2013&quot;&gt;Lance Stout&lt;/a&gt; (an &amp;#x26;yet team member), and &lt;a href=&quot;http://wiki.xmpp.org/web/Philipp_Hancke_for_Council_2013&quot;&gt;Philipp Hancke&lt;/a&gt; were elected into the XMPP Standards Foundation (XSF) Council.
This council is the five people in charge of approving extensions to XMPP.
It is encouraging to see two people who have been contributing to XMPP tools for the web elected to this council.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://wiki.xmpp.org/web/Mike_Taylor_for_Board_2013&quot;&gt;Mike &quot;Bear&quot; Taylor&lt;/a&gt; (another &amp;#x26;yet team member) was also re-elected to the board, which has been making the advantages of XMPP clear to developers over the years.
But XMPP has always been a tough-sell for web developers.&lt;/p&gt;
&lt;p&gt;JavaScript is ill-equipped to deal with streaming XML.
Additionally, modern development tends to use language data structures (namely JSON) for APIs, databases, and protocols.
As such, web developers have a difficult time dealing with XMPP, finding XML stanzas to be archaic.&lt;/p&gt;
&lt;p&gt;Web developers are a pragmatic bunch, preferring simple interfaces rather than difficult-to-implement interfaces, regardless of additional benefits.
Due to this, the XMPP community has changed their attitude and tactics.
They used to try and convince web developers to use XMPP whereas now they are bringing XMPP to web developers with more web-friendly interfaces.&lt;/p&gt;
&lt;p&gt;Lance Stout and &lt;a href=&quot;http://twitter.com/lloydwatkin&quot;&gt;Lloyd Watkin&lt;/a&gt; have independently brought us libraries for higher level JSON APIs and modern WebSockets for XMPP.
These competing efforts are &lt;a href=&quot;https://github.com/legastero/stanza.io&quot;&gt;Stanza.io&lt;/a&gt; and &lt;a href=&quot;https://xmpp-ftw.jit.su/&quot;&gt;XMPP-FTW&lt;/a&gt;.
Along with Lance&apos;s efforts on the XMPP over WebSockets standard, this helps bridge the gap to XMPP.&lt;/p&gt;
&lt;p&gt;In response to the XMPP communities attitude change, the web community has responded in kind.
Nowhere was this more clear than at this year&apos;s RealtimeConf and WebRTC Camp in Portland, OR.
Federation was the main theme of RealtimeConf, and WebRTC (video calling and data peering for the web) was the new hot technology.
It quickly became clear that XMPP&apos;s Jingle was the perfect way to federate WebRTC.&lt;/p&gt;
&lt;p&gt;Lance Stout and Philipp Hancke presented Jingle calls working between Lance&apos;s &lt;a href=&quot;https://github.com/legastero/stanza.io&quot;&gt;Stanza.io&lt;/a&gt; and Philipp&apos;s &lt;a href=&quot;https://github.com/ESTOS/strophe.jingle&quot;&gt;Strophe-Jingle&lt;/a&gt;.
Combining a new simple JSON API to XMPP, XMPP&apos;s powerful Jingle extension, and WebRTC, it became immediately clear to those who attended that federated peering had arrived to the web.&lt;/p&gt;
&lt;p&gt;The XSF and community have been busy on other efforts as well.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Peter-Saint Andre has written a &lt;a href=&quot;https://stpeter.im/journal/1496.html&quot;&gt;manifesto&lt;/a&gt; for making the XMPP network a TLS secure-only network.&lt;/li&gt;
&lt;li&gt;The new &lt;a href=&quot;http://xmpp.net&quot;&gt;xmpp.net&lt;/a&gt; site now has tests for verifying encryption.&lt;/li&gt;
&lt;li&gt;New users will soon have an easier way to discover and register on public servers.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://xmpp.org&quot;&gt;xmpp.org&lt;/a&gt; will be rebranding to focus on helping new developers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;XMPP brings strong identity, rosters and presence, capabilities negotiation, data-peering, and countless other capabilities with it.
With these efforts, the capabilities of web applications take a huge leap forward.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Human JavaScript is available now.]]></title><description><![CDATA[After years spent compiling, eight months of writing, editing and rewriting, figuring out the process for epublishing and learning how to…]]></description><link>https://blog.andyet.com/2013/10/14/human-javascript-now-available/</link><guid isPermaLink="false">https://blog.andyet.com/2013/10/14/human-javascript-now-available/</guid><pubDate>Mon, 14 Oct 2013 17:36:00 GMT</pubDate><content:encoded>&lt;p&gt;After years spent compiling, eight months of writing, editing and rewriting, figuring out the process for epublishing and learning how to use &lt;a href=&quot;https://gumroad.com/&quot;&gt;Gumroad&lt;/a&gt; (which we highly recommend!) – &lt;a href=&quot;https://gumroad.com/l/humanjs&quot;&gt;Human JavaScript is finally available&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;As an experiment, we released it a week ago to see what the reaction would be and so far the feedback has been overwhelmingly positive. Here&apos;s what people have said about Human JavaScript in the past week:&lt;/p&gt;
&lt;p&gt;&quot;...&lt;strong&gt;required reading&lt;/strong&gt; for every JavaScript Developer.&quot; &lt;a href=&quot;https://twitter.com/svenlito&quot;&gt;@svenlito&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&quot;Human Javascript is one of these books I would have loved to have read two years ago. Great book!&quot; &lt;a href=&quot;https://twitter.com/normanrz&quot;&gt;@normanrz&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&quot;Never thought I&apos;d &lt;strong&gt;enjoy reading a book about JS&lt;/strong&gt;. And it&apos;s a great resource for the new guy.&quot; &lt;a href=&quot;https://twitter.com/KevSpence&quot;&gt;@KevSpence&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&quot;The best book you can buy right now to &lt;strong&gt;get a grip on frontend JavaScript&lt;/strong&gt;&quot; &lt;a href=&quot;https://twitter.com/janl&quot;&gt;@janl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&quot;This looks like what I&apos;ve wanted to exist to give to people stuck in $-all-the-things land so many times. &lt;strong&gt;Insta-buy&lt;/strong&gt;.&quot; &lt;a href=&quot;https://twitter.com/JeremyMorrell&quot;&gt;@JeremyMorrell&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&quot;...winner for best intro vid.&quot; &lt;a href=&quot;https://twitter.com/voodootikigod&quot;&gt;@voodootikigod&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And now it can be yours for &lt;a href=&quot;https://gumroad.com/l/humanjs&quot;&gt;$29&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Your purchase includes &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;100+ pages of clear explanations&lt;/li&gt;
&lt;li&gt;Code examples&lt;/li&gt;
&lt;li&gt;Project skeleton for JavaScript applications&lt;/li&gt;
&lt;li&gt;A lifetime subscription to updates of the book&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not to mention a foreward by &lt;a href=&quot;https://twitter.com/janl&quot;&gt;Jan Lehnardt&lt;/a&gt;, Open Source Software developer responsible for all sorts of cool things like &lt;a href=&quot;http://hood.ie/&quot;&gt;hood.ie&lt;/a&gt;, &lt;a href=&quot;https://github.com/janl/mustache.js/&quot;&gt;mustache.js&lt;/a&gt; and &lt;a href=&quot;http://couchdb.apache.org/&quot;&gt;Apache CouchDB&lt;/a&gt;. Read an excerpt from it at humanjavascript.com. &lt;/p&gt;
&lt;p&gt;Human JavaScript is available in &lt;a href=&quot;https://gumroad.com/l/humanjs&quot;&gt;DRM-free Kindle, ePub, or PDF&lt;/a&gt;. 100 user site licenses are also available for your dev team for &lt;a href=&quot;https://gumroad.com/l/humanjs&quot;&gt;$249&lt;/a&gt;. We&apos;ll keep you posted on the other publishing options we&apos;ve been looking into.&lt;/p&gt;
&lt;p&gt;Henrik also added some info to the Human JavaScript site last week, if you&apos;re needing persuading. Check out the table of contents on the book at &lt;a href=&quot;http://humanjavascript.com/#contents&quot;&gt;humanjavascript.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have questions, make sure to ping &lt;a href=&quot;https://www.twitter.com/HenrikJoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; on Twitter! Feedback from you helps us make the book a more agile and accurate resource for every reader.&lt;/p&gt;
&lt;p&gt;We look forward to your reviews!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Realtime Week scholarships for women]]></title><description><![CDATA[Inspired by a tweet from @seriouspony, we are offering a special discount scholarship ticket with the aim of increasing the number of…]]></description><link>https://blog.andyet.com/2013/09/29/realtime-week-scholarships-for-women/</link><guid isPermaLink="false">https://blog.andyet.com/2013/09/29/realtime-week-scholarships-for-women/</guid><pubDate>Sun, 29 Sep 2013 08:45:00 GMT</pubDate><content:encoded>&lt;p&gt;Inspired by &lt;a href=&quot;https://twitter.com/seriouspony/status/383984999730397184&quot;&gt;a tweet from @seriouspony&lt;/a&gt;, we are offering a special discount scholarship ticket with the aim of increasing the number of amazing women part of the RealtimeConf community. (We already have some truly incredible women part of this community, but we&apos;d sure love to see more.)&lt;/p&gt;
&lt;p&gt;This ticket is &lt;strong&gt;just $399 for women who will commit to submitting a talk at next year&apos;s RealtimeConf.&lt;/strong&gt;This includes admission to &lt;a href=&quot;http://2013.realtimeconf.com&quot;&gt;RealtimeConf&lt;/a&gt; and &lt;a href=&quot;http://2013.webrtccamp.com&quot;&gt;WebRTC Camp&lt;/a&gt;. (Don&apos;t miss checking out the &lt;a href=&quot;http://2013.realtimeconf.com/content&quot;&gt;RealtimeConf content&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;This is a savings of over $600 off the ticket price and there will be a limited number of these tickets available.&lt;/p&gt;
&lt;p&gt;Given the significant role women have played on making our team better and that &lt;em&gt;8 of the 10&lt;/em&gt; best conference talks I&apos;ve heard in 2013 were delivered by women, this is an investment in the future quality of overall culture and presentations at RealtimeConf.&lt;/p&gt;
&lt;p&gt;Please help us spread the word!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://tito.io/&amp;#x26;yet/realtimeconf-2013?release_id=ryoo0mtbx6o&quot;&gt;$399 Realtime Week scholarship ticket&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[I, for one, do not welcome our new telecom masters—but WebRTC is going to break the whole game open anyway.]]></title><description><![CDATA[People have a very special distaste for telecoms.Between wiretapping, egregious data roaming and text messaging charges, the unreadability…]]></description><link>https://blog.andyet.com/2013/09/27/webrtc-is-going-to-break-the-whole-game-open/</link><guid isPermaLink="false">https://blog.andyet.com/2013/09/27/webrtc-is-going-to-break-the-whole-game-open/</guid><pubDate>Fri, 27 Sep 2013 08:11:00 GMT</pubDate><content:encoded>&lt;p&gt;People have a very special distaste for telecoms.&lt;/p&gt;
&lt;p&gt;Between wiretapping, egregious data roaming and text messaging charges, the unreadability of our phone bills, and carrier lock-in, we have plenty of reasons. Add in the fact that we consider ourselves entirely dependent on them and we&apos;re all the more resentful and cynical.&lt;/p&gt;
&lt;p&gt;But forget the traditional telecoms for a minute.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Google, Microsoft, Apple, and Facebook are truly the new telecoms&lt;/strong&gt;—each within the last few years has built or bought a communication platform of their own.&lt;/p&gt;
&lt;p&gt;The thing is: we&apos;d never let telecoms do what we&apos;re letting them get away with: zero interoperability and giving them complete ownership of our ability to communicate with each other. (Can you even imagine if you had to have a Verizon phone to call Verizon customers and an AT&amp;#x26;T phone to call AT&amp;#x26;T customers?)&lt;/p&gt;
&lt;p&gt;The fierceness of these tech companies&apos; competition with one another is what keeps users largely in control, yet we put up with them growing more siloed instead of more integrated. It&apos;s been truly shocking to see Google take steps &lt;em&gt;away&lt;/em&gt; from interoperability and federation.&lt;/p&gt;
&lt;p&gt;It&apos;s interesting: major carriers have said &lt;a href=&quot;http://arstechnica.com/information-technology/2013/01/the-telephone-network-is-obsolete-get-ready-for-the-all-ip-telco/&quot;&gt;they want to get away from the public switched telephone network (PSTN) and move to all Internet-based telephony services&lt;/a&gt;. No doubt, they see what their future competition is doing, how far ahead of them they are, and they understand plainly they&apos;re entirely hindered in putting up a fair fight by decades of regulative legislation, not to mention entirely bound to aging infrastructure.&lt;/p&gt;
&lt;p&gt;This is not a complaint about regulation or a defense of telecoms. &lt;/p&gt;
&lt;p&gt;It&apos;s quite simple: in the long run, traditional carriers have already lost unless they can be in a position to compete on the same grounds that tech companies can.&lt;/p&gt;
&lt;p&gt;And as much as we think of the cool well-funded tech startups with telco APIs as &quot;disruptive&quot;, we can still throw those in with the lot. Forget what their teams say, their paymasters&apos; desires are for them to be bought by one of the biggest tech companies, or IPO and join them.&lt;/p&gt;
&lt;p&gt;The fact is, there&apos;s no reasonable short-term economic incentive for any of these businesses (old-school telcos or tech telcos) to operate any differently from how they are. They&apos;re simply protecting their market share and aiming to maximize their profits.&lt;/p&gt;
&lt;p&gt;But open communication is the heart of the web. &lt;/p&gt;
&lt;p&gt;We should be demanding absolute interoperability of communication from the telecoms of the web, just the same as we demand it from carriers—and that communication should be as open, secure, and as free from invasion of privacy as it can possibly be made to be.&lt;/p&gt;
&lt;p&gt;One of the valid criticisms of Prism is: even if the NSA&apos;s data collection program were used responsibly and only had benevolent intentions (doubtful), the centralization of that much power of information makes it ripe for abuse. The same is the case for our oligarchic &quot;techlecom&quot; silos.&lt;/p&gt;
&lt;p&gt;The web needs an answer to this—and badly.&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet, we feel that the revolution of WebRTC poses a brand new turning point for the web and we have been actively engaged in taking advantage of this opportunity to the best of our ability. We&apos;re a fully bootstrapped company and we&apos;ve poured an immense amount of our time, energy, and money into WebRTC because we believe in its power to fully undermine the status quo.&lt;/p&gt;
&lt;p&gt;One of the reasons we started RealtimeConf was we were part of several web tech communities, plus the XMPP community—and we were eager to get them together for a variety of reasons.&lt;/p&gt;
&lt;p&gt;The XMPP community has a remarkably similar spirit to those who believe in the Open Web. These are folks who want to see communication open and free-as-in-speech, if not free-as-in-beer too. Interoperability is of chief concern in the XMPP community. This community is passionate about the problem of truly open and free communication, which is why they&apos;ve put years of energy into solving the problems that all of us who rely on IM every day absolutely take for granted.&lt;/p&gt;
&lt;p&gt;But the XMPP community is decidedly &lt;em&gt;not&lt;/em&gt; made up of web developers. Most of the community are enterprise-focused in their work and background, and quite centrally focused on &lt;em&gt;Internet&lt;/em&gt; communication much more than the web.&lt;/p&gt;
&lt;p&gt;This is an important distinction to understand. The web, specifically, is one of humanity&apos;s greatest equalizers. The Internet may be the wheel and the internal combustion engine, but the web is the car.&lt;/p&gt;
&lt;p&gt;In contrast to the XMPP community, the web developer communities we&apos;ve been part of absolutely detest the slow-moving and overwrought standards body rigamarole and don&apos;t want anything to do with it. And while developers who are building Internet communication services for enterprise don&apos;t feel hassled dealing with XML, to web developers, pouring XML on a complex and aging streaming API sounds about as attractive as a kick in the teeth.&lt;/p&gt;
&lt;p&gt;Yet although we as web developers decry silos, we further participate in the siloing of the web by failing to aim for interoperability into our own experiments. Dozens of projects come and go under the guise of building open networks, but as my friend and mentor &lt;a href=&quot;http://twitter.com/julien51&quot;&gt;Julien Genestoux&lt;/a&gt; put it, &quot;Everyone wants to reinvent the wheel just so they can put their name on it.&quot; &lt;/p&gt;
&lt;p&gt;There are numerous &quot;open&quot; protocols that have emerged around WebRTC, but unfortunately it seems most are set up to describe how other systems can federate with the authors of those protocols. We&apos;ve yet to see a company interested in selling WebRTC services point to documentation for using a publicly accepted standard. There are a bunch of WebRTC &quot;standards&quot; that essentially say, &quot;You bet you can call us from anywhere! Just buy or build a Verizon phone first.&quot; &lt;/p&gt;
&lt;p&gt;This isn&apos;t to shame anyone building those—they&apos;re making cool stuff, it&apos;s just that this is how we end up with 15 competing standards:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://xkcd.com/927/&quot;&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/standards.png&quot; alt=&quot;xkcd comic 927&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So, as we at &amp;#x26;yet see it, the problems look like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The web needs open, secure, independent, interoperable communication channels for the preservation of the freedom of the web (and, perhaps, its people).&lt;/li&gt;
&lt;li&gt;XMPP is foreign overkill complexity for web developers.&lt;/li&gt;
&lt;li&gt;Web developers have no options for standardized federated communication that&apos;s not proprietary.&lt;/li&gt;
&lt;li&gt;The XMPP community has historically been disinvolved from the web developer community. (This has been changing the last few years.)&lt;/li&gt;
&lt;li&gt;The web community has historically &lt;em&gt;only&lt;/em&gt; built uninteroperable communication services.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The rapid adoption of WebRTC provides a dramatic opportunity for a turning point: here is the first communication API to be added to web browsers—and, even better, it&apos;s peer-to-peer (once you have signaling in place). And undoubtedly, the concerns the XMPP community has focused on for years have become suddenly and powerfully relevant to the web. An imperfect, but battle-hardened and well-distributed standard is exactly what we need to avoid the poison of 15 people reinventing the wheel.&lt;/p&gt;
&lt;p&gt;What we need right now is &lt;em&gt;unity&lt;/em&gt; and &lt;em&gt;diversity&lt;/em&gt; — unity around protocol with diverse implementations.&lt;/p&gt;
&lt;p&gt;Amazing things are afoot, even if they&apos;re out of view of the mainstream WebRTC hype:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;New abstraction libraries that make XMPP friendly to the web (like &lt;a href=&quot;https://twitter.com/lloydwatkin&quot;&gt;Lloyd Watkin&lt;/a&gt;&apos;s &lt;a href=&quot;https://github.com/lloydwatkin/xmpp-ftw&quot;&gt;XMPP-FTW&lt;/a&gt; and our own &lt;a href=&quot;http://twitter.com/lancestout&quot;&gt;Lance Stout&lt;/a&gt;&apos;s &lt;a href=&quot;https://github.com/legastero/stanza.io&quot;&gt;Stanza.io&lt;/a&gt;). &lt;/li&gt;
&lt;li&gt;Our team has been sharing the WebRTC knowledge we&apos;ve gained building &lt;a href=&quot;http://simplewebrtc.com&quot;&gt;SimpleWebRTC&lt;/a&gt; and &lt;a href=&quot;http://talky.io&quot;&gt;Talky&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;We&apos;re benefiting from the knowledge of others like &lt;a href=&quot;https://github.com/ESTOS/strophe.jingle&quot;&gt;Strophe-jingle&lt;/a&gt; author &lt;a href=&quot;https://github.com/fippo&quot;&gt;Philipp Hancke&lt;/a&gt; signaling Jingle for WebRTC via JavaScript.&lt;/li&gt;
&lt;li&gt;New XMPP clients are under development, and some existing ones are augmenting with WebRTC signaling.&lt;/li&gt;
&lt;li&gt;Some awesome demos of interoperable XMPP+WebRTC clients are starting to take shape—and we know there are others out there building on this concept who we haven&apos;t even heard of yet!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&apos;s the secret about building a &quot;Skype killer&quot; as &lt;a href=&quot;http://blog.andyet.com/2013/09/26/what-the-heck-why-not&quot;&gt;we teased about yesterday&lt;/a&gt; — it&apos;s &lt;em&gt;only&lt;/em&gt; going to happen because a lot of people are independently working together. As it&apos;s been said: &lt;em&gt;It&apos;s amazing what you can get done if you don&apos;t care who gets credit.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you come to &lt;a href=&quot;http://2013.realtimeconf.com&quot;&gt;RealtimeConf&lt;/a&gt;, &lt;a href=&quot;http://2013.webrtccamp.com&quot;&gt;WebRTC Camp&lt;/a&gt;, and the &lt;a href=&quot;http://wiki.xmpp.org/web/Summit_14&quot;&gt;US XMPP Summit&lt;/a&gt; this October, you&apos;ll find this thread will undoubtedly be one of the key things discussed. &lt;/p&gt;
&lt;p&gt;Being part of it, you&apos;ll help define the future with the folks mentioned above and other key doers in this field.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[What the heck. Why not?]]></title><description><![CDATA[Wouldn't it be cool if someone built a federated, interoperable, open source, and super hackable "Skype killer" built on WebRTC and XMPP and…]]></description><link>https://blog.andyet.com/2013/09/26/what-the-heck-why-not/</link><guid isPermaLink="false">https://blog.andyet.com/2013/09/26/what-the-heck-why-not/</guid><pubDate>Thu, 26 Sep 2013 09:20:00 GMT</pubDate><content:encoded>&lt;p&gt;Wouldn&apos;t it be cool if someone built a federated, interoperable, open source, and super hackable &quot;Skype killer&quot; built on WebRTC and XMPP and released it at &lt;a href=&quot;http://2013.realtimeconf.com&quot;&gt;RealtimeConf&lt;/a&gt;?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[EdgeConf 2013 Realtime panel discussion]]></title><description><![CDATA[I had the privilege to attend EdgeConf 2013 as a panelist and opening speaker for the Realtime Data discussion.It was an incredible, deeply…]]></description><link>https://blog.andyet.com/2013/09/25/edgeconf-webrtc/</link><guid isPermaLink="false">https://blog.andyet.com/2013/09/25/edgeconf-webrtc/</guid><pubDate>Wed, 25 Sep 2013 16:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I had the privilege to attend &lt;a href=&quot;http://edgeconf.com/2013-nyc/&quot;&gt;EdgeConf 2013&lt;/a&gt; as a panelist and opening speaker for the Realtime Data discussion.&lt;/p&gt;
&lt;p&gt;It was an incredible, deeply technical conference with an interesting discussion/debate format.&lt;/p&gt;
&lt;p&gt;Here&apos;s the video from the panel:&lt;/p&gt;
&lt;iframe width=&quot;500&quot; height=&quot;281&quot; src=&quot;//www.youtube.com/embed/Al3SEbeK61s?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;The slides from my talk can be found &lt;a href=&quot;https://speakerdeck.com/henrikjoreteg/webrtc-intro-talk&quot;&gt;on speakerdeck&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It was a privilege to attend — I&apos;m very grateful to &lt;a href=&quot;https://twitter.com/triblondon&quot;&gt;Andrew Betts&lt;/a&gt; and &lt;a href=&quot;http://labs.ft.com/&quot;&gt;FT Labs&lt;/a&gt; for the opportunity to be there.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[C'mon get Hapi – building APIs with Hapi]]></title><description><![CDATA[Hapi is a web framework created by Walmart Labs that has many bells and whistles, including built in support for input validation and…]]></description><link>https://blog.andyet.com/2013/09/12/cmon-get-hapi/</link><guid isPermaLink="false">https://blog.andyet.com/2013/09/12/cmon-get-hapi/</guid><pubDate>Thu, 12 Sep 2013 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hapi is a web framework created by Walmart Labs that has many bells and whistles, including built in support for input validation and authentication, as well as a powerful plugin system.&lt;/p&gt;
&lt;p&gt;In this online course, &lt;a href=&quot;https://attendee.gotowebinar.com/register/5549422455379379713&quot;&gt;Introduction to Building APIs with Hapi&lt;/a&gt;, you will learn how to create a simple API, including query parameter and payload validation. We will also look at how to load and configure plugins.&lt;/p&gt;
&lt;p&gt;Plan on spending some time on September 25, 2013 say, around 11am (PDT) with &lt;a href=&quot;http://andyet.com/team/nlf/&quot;&gt;Nathan LaFreniere&lt;/a&gt;, our resident dev/ops badass, as he guides you through Hapi land and leads a Q&amp;#x26;A to fill you in on any lingering questions.&lt;/p&gt;
&lt;p&gt;LaFreniere is an endlessly talented developer with expertise in both building custom production systems and supporting complex realtime web apps. He&apos;s also created and contributed to a number of &lt;a href=&quot;http://labs.andyet.com/&quot;&gt;open source projects&lt;/a&gt;, many of which have become fundamental to our development process at &amp;#x26;yet.&lt;/p&gt;
&lt;p&gt;Register to attend &lt;a href=&quot;https://attendee.gotowebinar.com/register/5549422455379379713&quot;&gt;here&lt;/a&gt; for free. For updates and information on future online courses, sign up below with your email address and we promise we won&apos;t spam you.&lt;/p&gt;
&lt;div class=&quot;createsend-button&quot; style=&quot;height:22px;display:inline-block;&quot; data-listid=&quot;r/E0/988/C1A/0BB1405561920C1C&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot; async src=&quot;//btn.createsend1.com/js/sb.min.js?v=2&quot; class=&quot;createsend-script&quot;&gt;&lt;/script&gt;</content:encoded></item><item><title><![CDATA[Shame and security]]></title><description><![CDATA[Our response to another dev community's vulnerabilities says more about our personal insecurity than it does about their code's insecurity…]]></description><link>https://blog.andyet.com/2013/09/11/shame-and-security/</link><guid isPermaLink="false">https://blog.andyet.com/2013/09/11/shame-and-security/</guid><pubDate>Wed, 11 Sep 2013 05:03:00 GMT</pubDate><content:encoded>&lt;p&gt;Our response to another dev community&apos;s vulnerabilities says more about &lt;em&gt;our&lt;/em&gt; personal insecurity than it does about their code&apos;s insecurity.&lt;/p&gt;
&lt;p&gt;Full-stack web developers are generally a smart bunch—some exceptionally so, especially when you consider the increasing amount of complexity that must be navigated to build a modern web application.&lt;/p&gt;
&lt;p&gt;Developers are universally defensive about the security of their code—and even moreso, their chosen tools.&lt;/p&gt;
&lt;p&gt;Over the past year, there have been widely publicized vulnerabilities in Rails and Ruby. We&apos;ve admittedly seen developers in other communities point and laugh. In turn, the Node ecosystem has seen its share of vulnerabilities, including one that a couple evenings ago generated a prominent Twitter dustup between leading developers in different communities (which I&apos;m intentionally not going to link to).&lt;/p&gt;
&lt;p&gt;The security of a platform eventually becomes a running joke to everyone who doesn&apos;t use it. Being able to point at the so-called &quot;failures&quot; of others helps us justify the choices we make.&lt;/p&gt;
&lt;p&gt;Because we &lt;em&gt;ourselves&lt;/em&gt; are insecure. &lt;/p&gt;
&lt;p&gt;We are afraid. And by pointing and laughing when others fall, we are gathering our arsenal for the coming time when we, too, will be shamed for introducing a vulnerability.&lt;/p&gt;
&lt;p&gt;Yes, it&apos;s shame.&lt;/p&gt;
&lt;p&gt;Physical comedy and pratfalls are one of the most universal forms of humor. It doesn&apos;t matter if you understand the language or the culture, watching someone take a huge fall slipping on a banana peel or spill an entire soda on their pants makes us immediately laugh.&lt;/p&gt;
&lt;p&gt;That response is completely human—we are laughing that it&apos;s someone else who is experiencing the embarrassment we know that we are also capable of experiencing. It&apos;s relief.&lt;/p&gt;
&lt;p&gt;Relief that it&apos;s not us.&lt;/p&gt;
&lt;p&gt;Whether you are a developer building new things or one maintaining aging systems, part of your job is to write bugs and vulnerabilities. &lt;/p&gt;
&lt;p&gt;No doubt, that&apos;s a crass and disrespectful way to put it—no one &lt;em&gt;wants&lt;/em&gt; to write bugs, let alone security vulnerabilities. But the fact is  a moving target;even if the vulnerability in the code you&apos;re writing isn&apos;t revealed for years and not until some big 0day drops, it&apos;s still eventually insecure.&lt;/p&gt;
&lt;p&gt;So I get really depressed seeing the point-and-laugh about security between different software communities.&lt;/p&gt;
&lt;p&gt;Are we in high school? Is this Sharks vs. Jets in some stupid gang fight? Put down the spitballs, people, and stop depantsing each other.&lt;/p&gt;
&lt;p&gt;Web development across the board needs to culturally evolve to the place where (1) there&apos;s no shame in an honest vulnerability, and (2) we have mature and respectful ways to report, address, and disclose vulnerabilities.&lt;/p&gt;
&lt;p&gt;Shame should be reserved for unproductive name-calling and defensive reactions.&lt;/p&gt;
&lt;p&gt;Security matters—and it matters now more than ever. With corporations selling vulnerabilities in their software to the goverment, and a well-established black market buying and selling 0days for our software, can we stop with the cycle of smug finger-pointing, name-calling, and shaming in the open source community?&lt;/p&gt;
&lt;p&gt;Node developers and Rails developers are different—but we&apos;re probably as close to each other as any other developer communities out there. Which is the &lt;em&gt;entire reason&lt;/em&gt; for so much heightened vitriol between the two communities when a vulnerability is revealed. (See &lt;a href=&quot;http://en.wikipedia.org/wiki/Narcissism_of_small_differences&quot;&gt;Freud&apos;s &quot;narcissim of small differences&quot;&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Even if we hate how they cut his grass or educate their kids, it&apos;s not funny when our next door neighbors&apos; house is left unlocked and vandals are told about it.&lt;/p&gt;
&lt;p&gt;And when a vulnerability is identified in our neighbors&apos; software platform, there&apos;s no reason to point and laugh.&lt;/p&gt;
&lt;p&gt;It should instead inspire us to ask: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;Where is it possible I&apos;m already owned, but just don&apos;t know it yet?&quot;&lt;/li&gt;
&lt;li&gt;&quot;How can we respond better, faster, next time?&quot;&lt;/li&gt;
&lt;li&gt;&quot;How can we provide support and education?&quot;&lt;/li&gt;
&lt;li&gt;&quot;What are the blind spots in the way our community thinks about security?&quot;&lt;/li&gt;
&lt;li&gt;&quot;Where can we learn from other communities?&quot;&lt;/li&gt;
&lt;li&gt;&quot;How can we solve the overwhelming problem of the fact that our top open source producers completely lack the time and passion to maintain their aging projects?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thinking this way about all of the above is what &lt;a href=&quot;http://twitter.com/adam_baldwin&quot;&gt;Adam Baldwin&lt;/a&gt; has been teaching our team at &amp;#x26;yet over the past five years. &lt;/p&gt;
&lt;p&gt;This is what I love about &lt;a href=&quot;http://nodesecurity.io&quot;&gt;The Node Security Project&lt;/a&gt;—and why I have such respect for Adam: he&apos;s taking this show on the road.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[RedisConf 2013 canceled]]></title><description><![CDATA[We are canceling RedisConf 2013 due to lack of interest from attendees and sponsors.We have contacted the handful of ticket holders and we…]]></description><link>https://blog.andyet.com/2013/09/09/redisconf-2013-canceled/</link><guid isPermaLink="false">https://blog.andyet.com/2013/09/09/redisconf-2013-canceled/</guid><pubDate>Mon, 09 Sep 2013 17:03:00 GMT</pubDate><content:encoded>&lt;p&gt;We are canceling RedisConf 2013 due to lack of interest from attendees and sponsors.&lt;/p&gt;
&lt;p&gt;We have contacted the handful of ticket holders and we will be doing our best to help them work out their preferences.&lt;/p&gt;
&lt;p&gt;Ben Arent is still going to put together a great (but informal) Redis get-together on the same date in Portland, tentatively including a Redis hackathon in the morning and a meetup with talks in the afternoon where Salvatore Sanfilippo will be giving a full-length talk. These will be followed by an invitation to the RealtimeConf opening party. &lt;/p&gt;
&lt;p&gt;(One good thing is most everyone interested in RedisConf is also interested in RealtimeConf. In fact, there are only a couple of people who bought a ticket to RedisConf without accompanying it with a ticket to RealtimeConf and we&apos;re offering them to convert their RedisConf ticket to a full RealtimeConf ticket, saving $300.)&lt;/p&gt;
&lt;h3 id=&quot;why-cancel&quot;&gt;&lt;a href=&quot;#why-cancel&quot; aria-label=&quot;why cancel permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why cancel?&lt;/h3&gt;
&lt;p&gt;Let me first start by saying this is no one&apos;s fault but my own. We simply tried to take on too much at once and I went against my better judgement. I had decided &lt;em&gt;twice&lt;/em&gt; not to hold RedisConf 2013.&lt;/p&gt;
&lt;p&gt;RealtimeConf is the &quot;parent conference&quot; so to speak of RedisConf, and it&apos;s the most ambitious undertaking we&apos;ve ever put together. There was no way we were ever going to come close to breaking even on this year&apos;s event.&lt;/p&gt;
&lt;p&gt;RedisConf was going to be a great one-day conference accompanying it, but we needed it to break even or do considerably better than that—and we were counting too much on the popularity and interest people showed in it last year.&lt;/p&gt;
&lt;p&gt;I originally made the decision to cancel RedisConf 2013 because I thought demand was not going to be very high and we were quite interested in coupling RealtimeConf with a new WebRTC event.&lt;/p&gt;
&lt;p&gt;We believe RedisConf 2012 was primarily a success because of its timing with the release of Redis 2.6—we believed (and still believe) that its Lua scripting gives it unbelievable power and versatility and we were excited to gather people together from around the world to talk about it.&lt;/p&gt;
&lt;p&gt;I changed my mind right before following through with that decision. I reached out to Ben Arent to see if he was interested in helping with curation for RedisConf and he was.&lt;/p&gt;
&lt;p&gt;Ben has been terrific. &lt;/p&gt;
&lt;p&gt;He&apos;s put in a lot of energy and time and he&apos;s been great to work with. I simply haven&apos;t had the time to provide him with the support he&apos;s needed in order to make the event work. RedisConf 2013 not happening isn&apos;t Ben&apos;s failure, it&apos;s mine.&lt;/p&gt;
&lt;p&gt;Redis is a great tool. It has a wonderful community of users. It very well may justify an annual conference—it just will not be run by our team.&lt;/p&gt;
&lt;h3 id=&quot;realtimeconf&quot;&gt;&lt;a href=&quot;#realtimeconf&quot; aria-label=&quot;realtimeconf permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;RealtimeConf+++&lt;/h3&gt;
&lt;p&gt;There is definitely some good that is going to come out of this hard decision. Our team organizing RealtimeConf can focus even more on making that everything we want it to be and we&apos;ll have considerably more energy to do it.&lt;/p&gt;
&lt;p&gt;I can assure you, RealtimeConf is a can&apos;t-miss event if you care about the Open Web, are interested in the convergence of web technologies like WebRTC, WebSockets, XMPP, and more, and understand that now is the time to gather the people together who want to preserve our privacy and ensure open communication.&lt;/p&gt;
&lt;p&gt;We&apos;re aiming to bring together the most passionate and idealistic developers to share, dream, discuss, and hash out the future of a web that can overcome the dark spectre of corporate silos and government invasion that threaten to undermine what the powerfully positive democratic force the web can have.&lt;/p&gt;
&lt;h3 id=&quot;im-sorry&quot;&gt;&lt;a href=&quot;#im-sorry&quot; aria-label=&quot;im sorry permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;I&apos;m sorry.&lt;/h3&gt;
&lt;p&gt;If you were planning on being part of RedisConf, I am so sorry for letting you down.&lt;/p&gt;
&lt;p&gt;I feel this is the right decision, but it is most definitely painful to admit we&apos;ve failed you.&lt;/p&gt;
&lt;p&gt;Thank you for understanding.&lt;/p&gt;
&lt;p&gt;–Adam&lt;/p&gt;
&lt;p&gt;PS I intend to write a personal follow-up post-mortem on this at some point. There are some important things I feel I&apos;ve learned through it that I feel could be useful to share when I have a chance.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Now serving bite-sized online classes]]></title><description><![CDATA[Web technology and security change so rapidly it can be exhausting to keep up.We like to have lunch-and-learn type meetings at &yet to help…]]></description><link>https://blog.andyet.com/2013/08/21/bite-sized-online-classes/</link><guid isPermaLink="false">https://blog.andyet.com/2013/08/21/bite-sized-online-classes/</guid><pubDate>Wed, 21 Aug 2013 17:03:00 GMT</pubDate><content:encoded>&lt;p&gt;Web technology and security change so rapidly it can be exhausting to keep up.&lt;/p&gt;
&lt;p&gt;We like to have lunch-and-learn type meetings at &amp;#x26;yet to help keep each other in the loop on what we&apos;re learning. In the spirit of these timeless &quot;brownbags,&quot; we&apos;ve decided to create a series of short, introductory online classes.&lt;/p&gt;
&lt;p&gt;These bite-sized online classes will be focused on giving you a quick introduction to a topic and the chance to ask questions.&lt;/p&gt;
&lt;p&gt;The first class, Securing a Node.js Express App, will be taking place next week on Wednesday, August 28, 2013 at 11am Pacific Time with your guide &lt;a href=&quot;https://twitter.com/adam_baldwin&quot;&gt;Adam Baldwin&lt;/a&gt;, &amp;#x26;yet CSO, &lt;a href=&quot;http://liftsecurity.io&quot;&gt;^Lift Security&lt;/a&gt; team lead and founder of &lt;a href=&quot;http://nodesecurity.io&quot;&gt;The Node Security Project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Key takeaways will include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security lessons learned from having deployed Express apps in production.&lt;/li&gt;
&lt;li&gt;Overview of basic security headers and implementing them with helmet&lt;/li&gt;
&lt;li&gt;Implementing Cross-Site Request Forgery protection&lt;/li&gt;
&lt;li&gt;Session security considerations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adam is a top security expert and has spoken on web security issues at numerous events, including DEFCON, JSConf, and NodeConf and has advised the likes of GitHub, 37signals, and AT&amp;#x26;T on web application and API security.&lt;/p&gt;
&lt;p&gt;Click &lt;a href=&quot;https://attendee.gotowebinar.com/register/6429710155780305920&quot;&gt;here&lt;/a&gt; to sign up for &lt;a href=&quot;https://attendee.gotowebinar.com/register/6429710155780305920&quot;&gt;Securing a Node.js Express App&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can stay updated by following &lt;a href=&quot;https://www.twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; on Twitter for info on future classes.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Announcing the RealtimeConf US, RedisConf, and WebRTC Camp call for speakers and some more details!]]></title><description><![CDATA[First—some important news: We've changed the dates.Early this year, we announced dates for RealtimeConf, RedisConf, and a brand new, WebRTC…]]></description><link>https://blog.andyet.com/2013/06/11/announcing-the-realtimeconf-us-redisconf-and-webrt/</link><guid isPermaLink="false">https://blog.andyet.com/2013/06/11/announcing-the-realtimeconf-us-redisconf-and-webrt/</guid><pubDate>Tue, 11 Jun 2013 15:53:31 GMT</pubDate><content:encoded>&lt;p&gt;First—some important news: We&apos;ve changed the dates.&lt;/p&gt;
&lt;p&gt;Early this year, we announced dates for &lt;a href=&quot;http://2013.realtimeconf.com&quot;&gt;RealtimeConf&lt;/a&gt;, &lt;a href=&quot;http://2013.redisconf.com&quot;&gt;RedisConf&lt;/a&gt;, and a brand new, &lt;a href=&quot;http://2013.webrtccamp.com&quot;&gt;WebRTC-focused event&lt;/a&gt;. A short time later, our friends at LxJS announced their dates—which were unfortunately the same. We immediately reached out, discussed the mix-up, and determined that we were in the best position to change our dates.&lt;/p&gt;
&lt;p&gt;After getting back to the states after being part of a wonderful first-time RealtimeConf EU smashingly organized by Julien Genestoux, we&apos;ve reset dates and, in the meantime, we&apos;ve made tremendous headway on conference planning.&lt;/p&gt;
&lt;p&gt;Last year, we had a full week of Realtime events and we&apos;re just ramping that up a notch, by adding a full day focused on the most exciting realtime technology to hit the web: WebRTC.&lt;/p&gt;
&lt;p&gt;Here&apos;s what &lt;strong&gt;Realtime Week&lt;/strong&gt; looks like this year:&lt;/p&gt;
&lt;h3 id=&quot;redisconf-october-17&quot;&gt;&lt;a href=&quot;#redisconf-october-17&quot; aria-label=&quot;redisconf october 17 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;RedisConf: October 17&lt;/h3&gt;
&lt;p&gt;We are quite thrilled to be teaming up on RedisConf with &lt;a href=&quot;http://twitter.com/benarent&quot;&gt;Ben Arent&lt;/a&gt;, founder of RedisToGo, a significant contributor to the first RedisConf, and the organizer of the San Francisco Redis Meetup. Ben&apos;s passion for Redis makes him a perfect fit and we&apos;re excited to be working with him! Here&apos;s the &lt;a href=&quot;https://docs.google.com/forms/d/1pAFs4fDUB-JyphFCvoaqcvS37A7rAMniiLhtO2LIzPQ/viewform&quot;&gt;call for speakers for RedisConf&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;realtimeconf-us-october-18-19&quot;&gt;&lt;a href=&quot;#realtimeconf-us-october-18-19&quot; aria-label=&quot;realtimeconf us october 18 19 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;RealtimeConf US: October 18-19&lt;/h3&gt;
&lt;p&gt;Here&apos;s what attendees said about last year&apos;s RealtimeConf:&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/62112940&quot; height=&quot;281&quot; width=&quot;500&quot; allowfullscreen webkitallowfullscreen mozallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;http://vimeo.com/62112940&quot;&gt;RealtimeConf: in the words of attendees and speakers&lt;/a&gt; from &amp;#x26;&lt;a href=&quot;http://vimeo.com/andyet&quot;&gt;yet&lt;/a&gt; on &lt;a href=&quot;http://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You’ll really kick yourself if you miss this year—and it will most definitely sell out FAST.&lt;/p&gt;
&lt;p&gt;You can &lt;a href=&quot;https://tito.io/&amp;#x26;yet/realtimeconf-2013&quot;&gt;join the mailing list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&apos;s the &lt;a href=&quot;https://docs.google.com/a/andyet.net/forms/d/1dWnX2VQpQIavS27gxvgO7QkLOzz4LxC8Fdln8a5Vvms/viewform&quot;&gt;casting call for RealtimeConf&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;webrtc-camp-october-20&quot;&gt;&lt;a href=&quot;#webrtc-camp-october-20&quot; aria-label=&quot;webrtc camp october 20 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;WebRTC Camp: October 20&lt;/h3&gt;
&lt;p&gt;We’ll be co-organizing with a couple of our friends and heroes: &lt;a href=&quot;http://caseorganic.com&quot;&gt;Amber Case&lt;/a&gt; and &lt;a href=&quot;http://aaronparecki.com&quot;&gt;Aaron Parecki&lt;/a&gt; of Esri R&amp;#x26;D. Expect a mix of educational talks and demos of the amazing things people are already building with WebRTC. Here&apos;s the &lt;a href=&quot;https://docs.google.com/forms/d/1hHftI4nvGghZb5hqV94gv4QANoPsxhXXoGhHA_fTIpw/viewform&quot;&gt;call for speakers&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;us-xmpp-summit-october-21-22-independently-organized&quot;&gt;&lt;a href=&quot;#us-xmpp-summit-october-21-22-independently-organized&quot; aria-label=&quot;us xmpp summit october 21 22 independently organized permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;US XMPP Summit: October 21-22 (independently organized)&lt;/h3&gt;
&lt;p&gt;We&apos;re excited to see a continuation of developments that have emerged over the past year as a result of some of the community cross-pollination from RealtimeConf. We&apos;re looking forward to a lot of discussion around WebRTC + XMPP this year.&lt;/p&gt;
&lt;p&gt;Best way to stay in the loop on the planning for the 2013 US XMPP Summit is to &lt;a href=&quot;http://mail.jabber.org/mailman/listinfo/summit&quot;&gt;join the public mailing list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&apos;re interested in sponsoring &lt;a href=&quot;http://2013.redisconf.com&quot;&gt;RedisConf&lt;/a&gt;, &lt;a href=&quot;http://2013.realtimeconf.com&quot;&gt;RealtimeConf&lt;/a&gt;, or &lt;a href=&quot;http://2013.webrtccamp.com&quot;&gt;WebRTC Camp&lt;/a&gt;, you can reach out to &lt;a href=&quot;mailto:realtimeconf@realtimeconf.com&quot;&gt;realtimeconf@realtimeconf.com&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Welcome Karolina Szczur!]]></title><description><![CDATA[We’re happy to be able to announce Karolina Szczur (web, Twitter, GitHub) has joined the &yet team as lead interface designer/developer.We…]]></description><link>https://blog.andyet.com/2013/06/10/welcome-karolina-szczur/</link><guid isPermaLink="false">https://blog.andyet.com/2013/06/10/welcome-karolina-szczur/</guid><pubDate>Mon, 10 Jun 2013 14:05:58 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ec175534f6622be4f51b11e0c4b3d9e8/b4294/bio.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 600px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 58.27814569536424%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQBAgX/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgP/2gAMAwEAAhADEAAAAc95e97QJi//xAAaEAADAAMBAAAAAAAAAAAAAAABAgMAERIh/9oACAEBAAEFAkn3ioGjPgJPJ+xJ2f/EABYRAQEBAAAAAAAAAAAAAAAAAAABAv/aAAgBAwEBPwFNP//EABYRAQEBAAAAAAAAAAAAAAAAAAARAf/aAAgBAgEBPwHaj//EABwQAAICAgMAAAAAAAAAAAAAAAABAhEhQTFRYf/aAAgBAQAGPwLHOx9vBU3TGtULyQ2f/8QAGxABAAICAwAAAAAAAAAAAAAAAQAxESFBUZH/2gAIAQEAAT8hpvtlUODQeiY4I8R7mJUsVUtZ/9oADAMBAAIAAwAAABD0P//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxAwJQwL/8QAGREAAQUAAAAAAAAAAAAAAAAAAAERITFB/9oACAECAQE/EHFsnp//xAAeEAEAAwACAgMAAAAAAAAAAAABABEhMUFRYZGh4f/aAAgBAQABPxADnAhkbwfsPYUwWule+oFhDaeNY1/ta8ZHMCII1iafRCMLa/M//9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;karolina szczur&quot;
        title=&quot;&quot;
        src=&quot;/static/ec175534f6622be4f51b11e0c4b3d9e8/b4294/bio.jpg&quot;
        srcset=&quot;/static/ec175534f6622be4f51b11e0c4b3d9e8/0a254/bio.jpg 151w,
/static/ec175534f6622be4f51b11e0c4b3d9e8/c8fe0/bio.jpg 303w,
/static/ec175534f6622be4f51b11e0c4b3d9e8/b4294/bio.jpg 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We’re happy to be able to announce Karolina Szczur (&lt;a href=&quot;http://karolinaszczur.com&quot;&gt;web&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/fox&quot;&gt;Twitter&lt;/a&gt;, &lt;a href=&quot;https://github.com/karolinaszczur&quot;&gt;GitHub&lt;/a&gt;) has joined the &amp;#x26;yet team as lead interface designer/developer.&lt;/p&gt;
&lt;p&gt;We’ve been familiar with (and in awe of) Karolina’s work for some time and it’s quite an honor to be able to add her to our team. &lt;/p&gt;
&lt;p&gt;Karolina has been published in .Net Magazine, served as Editor at Smashing Magazine, and spoken at numerous JavaScript and design conferences around the world. She is also the former UX lead for Nodejitsu and has contributed design to The Node Firm, NodeCopter, and many open source projects. &lt;/p&gt;
&lt;p&gt;We’re excited to learn from her. &lt;/p&gt;
&lt;p&gt;What we’ve enjoyed about Karolina in the month-plus we’ve been able to work together is her clear vision for people-centered design, exceptional attention to interface detail, and the depth of experience from which she draws practical solutions to UI/UX problems. We’ve been blown away by her ability to communicate and provide honest, valuable feedback. &lt;/p&gt;
&lt;p&gt;Karolina’s focus on simplicity and pragmatic design makes her a perfect fit for our team’s preferred ways of building things. She’s already made dramatic contributions that will begin to show themselves soon in our products. &lt;/p&gt;
&lt;p&gt;She’s also a true quickdraw when it comes to pasting obscure but amazingly relevant animated gifs, repeatedly causing eruptions of laughter in our &lt;a href=&quot;http://andbang.com&quot;&gt;And Bang&lt;/a&gt; team chat with a perfectly timed post. &lt;/p&gt;
&lt;p&gt;I’d like to additionally note our thanks and gratitude for our mutual friend Jan Lehnardt for making the connection. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Riak, protocol buffer encoding, and you]]></title><description><![CDATA[Protocol buffer encoding is hard.I really wanted to use them, though, seeing as there's a pretty significant speed increase when you don't…]]></description><link>https://blog.andyet.com/2013/05/07/riak-protocol-buffer-encoding-and-you/</link><guid isPermaLink="false">https://blog.andyet.com/2013/05/07/riak-protocol-buffer-encoding-and-you/</guid><pubDate>Tue, 07 May 2013 09:38:26 GMT</pubDate><content:encoded>&lt;p&gt;Protocol buffer encoding is hard.&lt;/p&gt;
&lt;p&gt;I really wanted to use them, though, seeing as there&apos;s a pretty significant speed increase when you don&apos;t have the overhead of HTTP. &lt;/p&gt;
&lt;p&gt;Unfortunately, no one had written a node.js library for it. A couple of C bindings existed, but when I tried to use them, they either didn&apos;t even compile or I couldn&apos;t get them to work. That&apos;s when I had one of my all-too-common breakdowns, and decided to write my own. After all, anything for the sake of increased performance, right? &lt;/p&gt;
&lt;p&gt;Using &lt;a href=&quot;https://developers.google.com/protocol-buffers/&quot;&gt;Google&apos;s specifications&lt;/a&gt;, I got started. In order to use protocol buffer encoding in any language, you have to start by writing a definition file to describe what messages exist, and what they contain. That definition is used for both encoding and decoding packets. &lt;/p&gt;
&lt;p&gt;Obviously parsing these definitions is important, so that&apos;s where I started. The format of these files is reasonably consistent, so figuring out how to translate them into javascript objects wasn&apos;t too difficult. A couple of hours worth of work, and one big ugly loop later, I was feeling pretty good about myself. &lt;/p&gt;
&lt;p&gt;Once I had the definition parsed, I could start on writing actual data. This took a bit more effort; the protocol defines several different data types, and each of them is stored in its own unique way. To add to the confusion, you can also specify both repeated and optional elements. &lt;/p&gt;
&lt;p&gt;Since I was only writing this library to use with Riak, I decided to only use the data types that Riak uses in their definitions. Luckily for me, there are only two, varints and bytes. But what the heck is a varint? Back to the documentation I went. I learned that the varint is a fancy way to serialize numbers. According to Google&apos;s documentation: &lt;/p&gt;
&lt;p&gt;&quot;Each byte in a varint, except the last byte, has the most significant bit (msb) set – this indicates that there are further bytes to come. The lower 7 bits of each byte are used to store the two&apos;s complement representation of the number in groups of 7 bits, least significant group first.&quot; &lt;/p&gt;
&lt;p&gt;Wow, that&apos;s not confusing at all. I had to take some time for my brain to wrap around this one. Eventually, it came to me. Split your number up into 7 bit chunks, reverse the order, then set the first bit of each group to 1, except for the very last one. If the number you serialize is less than 127 (that&apos;s 7 bits), this is very easy since the result is just the number itself. &lt;/p&gt;
&lt;p&gt;Need to serialize 10? No problem, it&apos;s 10. That&apos;s the answer. 10. But what if you need to encode something much larger, say 500? This is where things get tricky. First things first, let&apos;s represent this in bits so it&apos;s easier to visualize: &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;111110100&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now we know we can only use 7 bits out of each byte since that first one is reserved, so let&apos;s break that into two almost bytes: &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;0000011 1110100&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now, you&apos;ll remember the documentation says &quot;least significant group first.&quot; Well, that just means things are backwards, so let&apos;s flip those around: &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1110100 0000011&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Okay, but we also have to tell the varint that we&apos;re using multiple bytes, so that means we have to set the most significant bit on the first byte to a 1. Tack a 1 on to the beginning of the first byte, and a 0 on the beginning of the second, taking them from almost bytes to actual bytes, and we&apos;ve got our varint representation of the number 500. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;11110100 00000011&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Wee, bits! &lt;/p&gt;
&lt;p&gt;Deserializing is the reverse, the first byte that doesn&apos;t have the most significant bit set is the last byte of your number. &lt;/p&gt;
&lt;p&gt;Drop the first bit of everything, and reverse all the bytes. Tada, there&apos;s your number. &lt;/p&gt;
&lt;p&gt;If you want to see what the code that actually does this in protobuf.js looks like, check out my butils project at &lt;a href=&quot;https://github.com/nlf/node-butils&quot;&gt;https://github.com/nlf/node-butils&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;Anyway, now that I&apos;ve probably lost 90% of everyone that was reading this with confusing math stuffs, I&apos;ll also explain how bytes or strings work. They&apos;re a much simpler critter – first we varint serialize the length of the string, then we append the bytes. That&apos;s it. &lt;/p&gt;
&lt;p&gt;Now, remember how I said that protocol buffer applications have a file that describes the available messages? &lt;/p&gt;
&lt;p&gt;Well, we have to store that information in the data stream too, so we know what data we actually have. How do you do that? &lt;/p&gt;
&lt;p&gt;Easy peasy. &lt;/p&gt;
&lt;p&gt;Each message is made up of several fields, each field has a number assigned to it as well as a type. An example from Google&apos;s documentation:
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
message Test1 {
required int32 a = 1;
required string b = 2;
}
&lt;/p&gt;
&lt;p&gt;Here, there are two fields, an int32 (that&apos;s a varint) named &quot;a&quot; at number 1, and a string named &quot;b&quot; at number 2. To build the header for each piece of data, you store the type of the data in the last three bits, and the field number in the other 5. Field number 1 is a varint, which is numerically a type of 0. So the header for that field would look like: &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;00001000&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Field 2, however, is a string which is numerically a type of 2, so its header would look like this: &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;00010010&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Append the actual data to the header, and you&apos;ve got a protocol buffer encoded message. Good for you! &lt;/p&gt;
&lt;p&gt;For repeated fields, you simply use the same header on each item. Optional fields, if they aren&apos;t there just don&apos;t add them to the data stream. Now we&apos;ve got all of the protocol buffer implementation that we need. &lt;/p&gt;
&lt;p&gt;But what about Riak? I guess that&apos;ll be a separate library. Let&apos;s call this one protobuf.js, and move on shall we? &lt;/p&gt;
&lt;p&gt;Riak prepends data messages with its own header. Their header is the 32 bit length of the internal Riak message code added to the length of the protocol buffer message, then the 8 bit message code itself, and the actual protocol buffer message. There&apos;s a small table of message codes in the Riak documentation, so this was really easy to add. &lt;/p&gt;
&lt;p&gt;Now we know how to encode data into protocol buffers, we know how to decode that data, we know how to add the appropriate headers, all that&apos;s left is to slap an interface on it and we&apos;ve got a client! &lt;/p&gt;
&lt;p&gt;The client simply translates the function call to a Riak message code, so client.get() becomes RpbGetReq. We encode the parameters as a protocol buffer message, we prepend the Riak header, and send it off to the server. The reply comes back with the message code RpbGetResp, so we make sure we&apos;ve got the right length of data (check your message length in the header!) then drop the Riak header, and decode the protocol buffer message. &lt;/p&gt;
&lt;p&gt;That&apos;s all there is to it. The Riak client portion of the code is relatively simple. A little connection management magic, some packet queueing to make sure we don&apos;t send another request before we get a response for the last one, and it&apos;s done. &lt;/p&gt;
&lt;p&gt;And that, my friends, is how a Riak protocol buffer library is born. &lt;/p&gt;
&lt;p&gt;After I &quot;finished&quot;, I went ahead and published what I had to npm, and basically forgot about it. Several months later, I got a pull request from Mathias Meyer (@roidrage on twitter and github) fixing a bug. &lt;/p&gt;
&lt;p&gt;Then another. &lt;/p&gt;
&lt;p&gt;After the third pull request, he told me that it&apos;s because he intended to integrate riakpbc as an alternate to the HTTP backend in riak-js. &lt;/p&gt;
&lt;p&gt;We collaborated some more over the next several weeks, and as of version 0.10 riak-js supports Riak&apos;s protocol buffer interface through riakpbc. &lt;/p&gt;
&lt;p&gt;Now that riakpbc and protobuf.js are being used in an already fairly widespread project, it&apos;s quite a bit more likely that bugs will be found and features will be requested. &lt;/p&gt;
&lt;p&gt;I&apos;ve seen a report from a user who was able to gain a 30% performance increase in his application, just by using protocol buffer encoding instead of HTTP, who wouldn&apos;t want that kind of performance for free? &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Press button, ship rocket]]></title><description><![CDATA[For those that don’t know, Ship Week (Ship It Monday, Brio and Úll) are happening right now in Dublin.For Ship It! Monday we announced that…]]></description><link>https://blog.andyet.com/2013/04/12/press-button-ship-rocket/</link><guid isPermaLink="false">https://blog.andyet.com/2013/04/12/press-button-ship-rocket/</guid><pubDate>Fri, 12 Apr 2013 10:56:16 GMT</pubDate><content:encoded>&lt;p&gt;For those that don’t know, &lt;a href=&quot;http://shipweek.in/dublin/&quot;&gt;Ship Week&lt;/a&gt; (Ship It Monday, Brio and Úll) are happening right now in Dublin.&lt;/p&gt;
&lt;p&gt;For Ship It! Monday we announced that And Bang 2.0 is now Beta, which you can now sign up to join the queue.&lt;/p&gt;
&lt;p&gt;And Bang is our team same-page-ification app that helps you and your team celebrate progress together throughout the day and ship like the wind.&lt;/p&gt;
&lt;p&gt;To join in the celebrations from home, we decided that it would be appropriate to launch a little something of our own. That something being a rocket, because what the heck, why not?&lt;/p&gt;
&lt;p&gt;In preparation for the launch we built a rocket that was almost 3&apos; tall. Then we painted it hot pink, and it was awesome.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Rocket-05eaeeae7d8b67bba6285d9837a6b71a.jpg&quot; alt=&quot;an actual rocket wow&quot;&gt;&lt;/p&gt;
&lt;p&gt;One of the great aspects of And Bang is that it’s built on a powerful API accompanied by a library, &lt;a href=&quot;https://npmjs.org/package/andbang&quot;&gt;andbang.js&lt;/a&gt;, that takes care of all the dirty bits and just lets you write code to interface with And Bang. We used this to launch the rocket.&lt;/p&gt;
&lt;p&gt;We installed node.js on a Raspberry Pi and set it up to listen for &quot;shipTask&quot; events. When that event was received it was verified that I did it and it was the right task for the launch. When one of the GPIO pins was set it would trip a relay that would supply voltage to the igniter and &lt;a href=&quot;http://blog.andyet.com/2013/mar/28/schwoosh/&quot;&gt;schoooo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1b62d5003fab0b3265c32771a7c23965/4ee7f/pi2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 486px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 74.8344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEL0lEQVQ4yy2Ta1DUZRSH/wJxUQRvXIIQAS8LrshFIGDZC3uBXdhlQVlgZVFjxVgQkCyNSEdN0CktU2ccy2mmrLGymZrEmUZGy3Ys1EYzxWK5zYoKgmI1ovXl6R2mD8+cmfOe+Z1z3nOOJAudT/TsEIIDAgny8yPY35/YmYFEBc3G3zeA53z9kCQJH0HADIlAP1/8BX4+PvjM8MFX+GeHJrAkXEaKPAcpITySBcGhLFmUgNlYjEGjx6gvpLyknMKCEiymYqxFFirK1lBuLSU6IoJAkfyFBaEY5GHMDRLiQfMIm5dE9tJkpLjw50nVKznw5Sn+mfqX+/fHuXmjl9u3PNzouc6DkXuMjT6cZqDfi1atIzwsktioKBo0sWgVSUQXmIRvFVEh4UjatJXoHHaOfn6KyQcPeTTxiKmpZ9y5+RtnvzjDiZPneHBvjLH/eW3Lq+RlKbAai3ijxkxLXS1ZeSpiYnLx9w9BshWZMNau5/Tpb/D09vOz+zLXrvzKwKUeLpz7if2Hv6b/9gAjw3cZH53g1vVeetxX6L1xm8G+YbpOf4siPZd4eSFzQsKQqiursLVs5crVazz5e4qxsYfcGxrm90uXOd99kc7dexnwDHF35D6evkGGBu/g9d5lUNg+IdjnGcBqd7EszTg9B2n3jnZOdXWJoDs8ffKUKcGzyUkmBgeEwBATY+NMjj/ir8k/p+3oyCjeIS/Dg4KhER5PPmZHx4fIVqrISs9Aqm9u5ePu7xjxekVbXjx/9ONxu+npvoD7/EWuXv0F9+UefrjkpvvH7zlzoZuvznZx4vhHHDx4iPePHKPM2c5StZLszGyk2rZmqk/uZ+Mn71J34gAb97TT2roJk2sDBY1OCva0Yjq6A/ORdtYf76Dq2FsoO1pJql9LRl0Fy8xriLFVktxcwSKlDsm6uQlD53bWvteGqXMnjfu24XpzM8btLuy7tqJsa0LfUIPy0DYsn3Xi+PQAapEg5Z1mUtrqWGZbT4azlFWCvPoapHKXnXyHDZXOgNpcTI1BjVKZR5oil+TUdBKzM4heGEeMYiWLLFriNDmk5qWJfcxhYbqOYPE2Pz6KiIRYUtLEH5rzFBQbtORrNCgzMylMS2GFPHkaWWISMpmc5fLlyJNX8EFnPO2N0SwNX8xOfTmq1CzioyNITBCnFxtH4mKZENSosRp0lOq0WFQqbKIyrVKDTq0lVyTLFEurM69Gb3Pw9v4ctmzJJVNfRa04hmanna0vr2PTuioiwxYQOXeOEFSrMRsMlAmq9TrqS0p4qXodlWsqKKq0U7XZSe0rTWiqHCgsdgy2aowWEeuopKWlHoPyRZaLdsNCZjF/1kwki0qJVZePtVAEFejZ69pEx659NDTsxdH4Os6mSja0OCl1OdEa8zGtNolFtmCy6CkrNXC4Qww1N5WQQD/mBQXwHxOhoQYYTqybAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;raspberry pi setup&quot;
        title=&quot;&quot;
        src=&quot;/static/1b62d5003fab0b3265c32771a7c23965/4ee7f/pi2.png&quot;
        srcset=&quot;/static/1b62d5003fab0b3265c32771a7c23965/29fe9/pi2.png 151w,
/static/1b62d5003fab0b3265c32771a7c23965/6728c/pi2.png 303w,
/static/1b62d5003fab0b3265c32771a7c23965/4ee7f/pi2.png 486w&quot;
        sizes=&quot;(max-width: 486px) 100vw, 486px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Quick recap...&lt;/p&gt;
&lt;p&gt;ShipTask &gt; iPhone &gt; 3g &gt; And Bang &gt; 3g &gt; mifi &gt; wifi &gt; pi &gt; relay &gt; igniter &gt; schoooo!&lt;/p&gt;
&lt;p&gt;And Bang is now Beta. Please go check out and enjoy And Bang 2.0, we think your team will enjoy using it as much as we&apos;ve enjoyed building it.&lt;/p&gt;
&lt;p&gt;Watch the recorded event here:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; allowfullscreen src=&quot;https://www.youtube.com/embed/7xX10KEPLFM&quot; frameborder=&quot;0&quot; height=&quot;315&quot;&gt;&lt;/iframe&gt;</content:encoded></item><item><title><![CDATA[Ship love]]></title><description><![CDATA[Buried in email. Overwhelmed by your backlog. Ugh.We built And Bang cos we're tired of tools that make us feel bad about doing work we love…]]></description><link>https://blog.andyet.com/2013/04/08/ship-love/</link><guid isPermaLink="false">https://blog.andyet.com/2013/04/08/ship-love/</guid><pubDate>Mon, 08 Apr 2013 10:35:03 GMT</pubDate><content:encoded>&lt;iframe src=&quot;https://player.vimeo.com/video/60772911&quot; height=&quot;281&quot; width=&quot;500&quot; allowfullscreen webkitallowfullscreen mozallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Buried in email. Overwhelmed by your backlog. Ugh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We built And Bang cos we&apos;re tired of tools that make us feel bad about doing work we love.&lt;/strong&gt; &lt;em&gt;(Aren&apos;t you?)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And Bang is here to help you and your team:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stay on the same page&lt;/li&gt;
&lt;li&gt;celebrate progress together throughout the day&lt;/li&gt;
&lt;li&gt;ship like the wind&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And Bang is shared tasks and team chat.&lt;/p&gt;
&lt;p&gt;And Bang was built for teams like yours who want to spend less time managing the work they&apos;re going to do—and more time getting it done.&lt;/p&gt;
&lt;p&gt;And Bang is now in beta.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://andbang.com&quot;&gt;Add your email&lt;/a&gt; at andbang.com to join the queue!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Schwoosh!]]></title><description><![CDATA[Starting this Friday, our awesome And Bang 1.0 customers will be receiving invitations to the And Bang 2.0 private beta.We built And Bang…]]></description><link>https://blog.andyet.com/2013/03/28/schwoosh/</link><guid isPermaLink="false">https://blog.andyet.com/2013/03/28/schwoosh/</guid><pubDate>Thu, 28 Mar 2013 18:21:03 GMT</pubDate><content:encoded>&lt;iframe src=&quot;https://player.vimeo.com/video/55830910&quot; height=&quot;281&quot; width=&quot;500&quot; allowfullscreen webkitallowfullscreen mozallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Starting this Friday, our awesome And Bang 1.0 customers will be receiving invitations to the &lt;a href=&quot;http://next.andbang.com&quot;&gt;And Bang 2.0&lt;/a&gt; private beta.&lt;/p&gt;
&lt;p&gt;We built And Bang because we&apos;re tired of tools that make us feel bad about doing work we love. &lt;em&gt;(Aren&apos;t you?)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We believe you should do the work you love in a way you love.&lt;/p&gt;
&lt;p&gt;And Bang lets your team:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;share tasks&lt;/li&gt;
&lt;li&gt;see who&apos;s working on what, right now&lt;/li&gt;
&lt;li&gt;chat with everyone or individually with teammates&lt;/li&gt;
&lt;li&gt;celebrate progress together throughout the day&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;...all in realtime.&lt;/p&gt;
&lt;p&gt;Between now and April 8, we’ll also start to roll out a few invites to the private beta in anticipation of sending a slew of them during &lt;a href=&quot;http://shipweek.in/dublin&quot;&gt;Ship Week&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;To request your invite to the private beta, just &lt;a href=&quot;http://next.andbang.com&quot;&gt;drop your email here&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Signalmaster: a WebRTC signaling server]]></title><description><![CDATA[Today, we're open sourcing signalmaster.Paired with SimpleWebRTC.js, this is all you need to set up and serve WebRTC video calls. Happy…]]></description><link>https://blog.andyet.com/2013/03/04/signalmaster-a-webrtc-signaling-server/</link><guid isPermaLink="false">https://blog.andyet.com/2013/03/04/signalmaster-a-webrtc-signaling-server/</guid><pubDate>Mon, 04 Mar 2013 11:11:56 GMT</pubDate><content:encoded>&lt;p&gt;Today, we&apos;re open sourcing &lt;a href=&quot;https://github.com/andyet/signalmaster&quot;&gt;signalmaster&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Paired with &lt;a href=&quot;https://github.com/HenrikJoreteg/SimpleWebRTC&quot;&gt;SimpleWebRTC.js&lt;/a&gt;, this is all you need to set up and serve WebRTC video calls. &lt;/p&gt;
&lt;p&gt;Happy WebRTCing! &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing SimpleWebRTC.js and conversat.io]]></title><description><![CDATA[We're announcing two WebRTC projects today: SimpleWebRTC.js and conversat.io.WebRTC is one of the most exciting additions to HTML5, enabling…]]></description><link>https://blog.andyet.com/2013/02/22/introducing-simplewebrtcjs-and-conversatio/</link><guid isPermaLink="false">https://blog.andyet.com/2013/02/22/introducing-simplewebrtcjs-and-conversatio/</guid><pubDate>Fri, 22 Feb 2013 16:25:00 GMT</pubDate><content:encoded>&lt;p&gt;We&apos;re announcing two WebRTC projects today: &lt;a href=&quot;http://simplewebrtc.com&quot;&gt;SimpleWebRTC.js&lt;/a&gt; and &lt;a href=&quot;http://conversat.io&quot;&gt;conversat.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;WebRTC is one of the most exciting additions to HTML5, enabling direct peer-to-peer connections for video and audio streaming. We’ve been playing with WebRTC for almost a year now, including helping clients like AT&amp;#x26;T put it into play.&lt;/p&gt;
&lt;p&gt;One conclusion we&apos;ve come to is that WebRTC should be easier for developers to work with if it&apos;s going to gain more adoption. More people should be playing with this new amazing technology, but there&apos;s a lot of annoying complexity when working with it. As Mikeal Rogers &lt;a href=&quot;https://twitter.com/mikeal/status/300016475329150976&quot;&gt;put it&lt;/a&gt;, &quot;It’s about 10x more complicated than WebSockets, and it’s taken 3 years to be where we are with WebSockets.&quot;&lt;/p&gt;
&lt;h3 id=&quot;simplewebrtcjs&quot;&gt;&lt;a href=&quot;#simplewebrtcjs&quot; aria-label=&quot;simplewebrtcjs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;SimpleWebRTC.js&lt;/h3&gt;
&lt;p&gt;We created &lt;a href=&quot;http://simplewebrtc.com&quot;&gt;SimpleWebRTC.js&lt;/a&gt; to make building things with WebRTC easy for frontend developers.&lt;/p&gt;
&lt;p&gt;You can use our sandbox &lt;a href=&quot;http://simplewebrtc.com&quot;&gt;SimpleWebRTC.com&lt;/a&gt; servers for development. In production, you’ll need to set up your own signaling server. You can use &lt;a href=&quot;https://github.com/andyet/signalmaster&quot;&gt;signalmaster&lt;/a&gt; or we can help you get one going -- just &lt;a href=&quot;mailto:contact@andyet.net&quot;&gt;drop us an email&lt;/a&gt; if you&apos;re interested.&lt;/p&gt;
&lt;h3 id=&quot;conversatio&quot;&gt;&lt;a href=&quot;#conversatio&quot; aria-label=&quot;conversatio permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;conversat.io&lt;/h3&gt;
&lt;p&gt;Today we’re also launching &lt;a href=&quot;http://conversat.io&quot;&gt;conversat.io&lt;/a&gt;, a video chat app for up to 6 people for you to use with your teams and people you want to have a quick video conversation with. We built conversat.io with SimpleWebRTC, of course. :)&lt;/p&gt;
&lt;p&gt;There&apos;s a nice little surprise to keep you busy while you wait, too. (Thanks, Fritzy!)&lt;/p&gt;
&lt;h3 id=&quot;caveats&quot;&gt;&lt;a href=&quot;#caveats&quot; aria-label=&quot;caveats permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Caveats&lt;/h3&gt;
&lt;p&gt;WebRTC has stabilized quite a bit recently, but it&apos;s still in flux. Chrome and Firefox Nightly support WebRTC, but we make no guarantees as this is all pretty green stuff.&lt;/p&gt;
&lt;p&gt;Try them out and let us know what you think. We’re eager to hear your feedback!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[AT&T, WebRTC, and &yet at CES]]></title><description><![CDATA[One of the main focuses of AT&T's Developer Summit at CES in Las Vegas this year was WebRTC. The AT&T WebRTC API truly untethers user phone…]]></description><link>https://blog.andyet.com/2013/01/15/att-webrtc-and-yet-at-ces/</link><guid isPermaLink="false">https://blog.andyet.com/2013/01/15/att-webrtc-and-yet-at-ces/</guid><pubDate>Tue, 15 Jan 2013 15:50:26 GMT</pubDate><content:encoded>&lt;p&gt;One of the main focuses of AT&amp;#x26;T&apos;s Developer Summit at CES in Las Vegas this year was WebRTC. &lt;/p&gt;
&lt;p&gt;The AT&amp;#x26;T WebRTC API truly untethers user phone numbers from their mobile device. When your phone number on your mobile rings, so can your browser and your tablet. It&apos;s the kind of thing that could make answering your phone or making a phone call from anywhere as easy as checking your email is today.&lt;/p&gt;
&lt;p&gt;&amp;#x26;yet was privileged to play a central role in AT&amp;#x26;T&apos;s work with WebRTC this year, alongside other partners like Ericsson and &lt;a href=&quot;http://voxeolabs.com&quot;&gt;Voxeo Labs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;#x26;yet has teamed up with &lt;a href=&quot;https://foundry.att.com/&quot;&gt;the AT&amp;#x26;T Foundry&lt;/a&gt; in Palo Alto to deliver several projects this past year. Some were shared at CES and most of those are featured at &lt;a href=&quot;https://js.att.io&quot;&gt;js.att.io&lt;/a&gt; and on &lt;a href=&quot;https://github.com/att-innovate&quot;&gt;AT&amp;#x26;T&apos;s GitHub account&lt;/a&gt;. (Note that at this time, you have to be a registered AT&amp;#x26;T Alpha Developer in order to use the API.)&lt;/p&gt;
&lt;p&gt;Aside from the various sample apps and tools we contributed, a key highlight was &lt;a href=&quot;http://js.att.io&quot;&gt;att.js&lt;/a&gt;, a JavaScript SDK for the AT&amp;#x26;T WebRTC API. (&lt;a href=&quot;https://github.com/att-innovate/att.js&quot;&gt;See the code on GitHub&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;You might expect the largest telecom in the US to be fighting &lt;em&gt;against&lt;/em&gt; a new and disruptive technology like WebRTC, but that&apos;s not been our experience with AT&amp;#x26;T—just the opposite, in fact. AT&amp;#x26;T wants to see WebRTC take off.&lt;/p&gt;
&lt;p&gt;The people involved in the developer programs at AT&amp;#x26;T are serious about WebRTC and building APIs that expose the power of AT&amp;#x26;T&apos;s existing infrastructure to developers. It&apos;s refreshing to see and rewarding to be part of.&lt;/p&gt;
&lt;p&gt;Our team at &amp;#x26;yet is happy to continue to be involved with AT&amp;#x26;T in 2013—and not just cos we ampersands gotta stick together ;)&lt;/p&gt;
&lt;p&gt;As an aside, we&apos;ve also really enjoyed collaborating this year with the amazing team at the AT&amp;#x26;T Foundry and the great people at Voxeo Labs, who are behind &lt;a href=&quot;http://tropo.com&quot;&gt;Tropo&lt;/a&gt; and &lt;a href=&quot;http://phono.com&quot;&gt;Phono&lt;/a&gt;, which both play a significant role in AT&amp;#x26;T&apos;s call control APIs.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[&Christmas or Christmas at &yet]]></title><description><![CDATA[the &yet office logo decorated with ornamentsSo if you’re anything like me and you are very excited about something, you want to celebrate…]]></description><link>https://blog.andyet.com/2012/12/24/christmas-or-christmas-at-yet/</link><guid isPermaLink="false">https://blog.andyet.com/2012/12/24/christmas-or-christmas-at-yet/</guid><pubDate>Mon, 24 Dec 2012 08:18:22 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;/photo_3-03302c21b3bd8a545b4b8ef9ad9b2a98.jpg&quot; alt=&quot;the &amp;#x26;yet office logo decorated with ornaments&quot;&gt;&lt;/p&gt;
&lt;p&gt;So if you’re anything like me and you are very excited about something, you want to celebrate it. &lt;/p&gt;
&lt;p&gt;If you are me, two of those things are Christmas and &amp;#x26;yet.&lt;/p&gt;
&lt;p&gt;This being my first Christmas with &amp;#x26;yet, I wasn’t entirely sure what to expect. I mean, I assumed it would be nothing short of awesomeness, I just couldn’t picture it in my head. &lt;/p&gt;
&lt;p&gt;I’m a words girl, so picturing stuff is a little difficult to begin with &lt;a href=&quot;http://instagram.com/p/RIdgXbs0ex/&quot;&gt;hipster marching band what?&lt;/a&gt;. But I’ve been fully immersed in this nerd-dev community for a while, so I was very curious about what style of celebration matched my team. &lt;/p&gt;
&lt;p&gt;Would they be the traditional, Santa Claus with the big, brightly decorated tree and the leg lamp in the window kind of people? &lt;/p&gt;
&lt;p&gt;Would they be sentimental with the nativity scene and maybe some understated classy gold and silver type scenario? &lt;/p&gt;
&lt;p&gt;Would they be the most expected type (troll) with maybe all Star Wars decor and perhaps some homemade nyan cat ornaments? &lt;/p&gt;
&lt;p&gt;Well, the answer is none of the above. &lt;/p&gt;
&lt;p&gt;I asked around to find out where the holiday decor was stored, and basically the answer was, “Leave me alone, blah blah push, Github, blah blah pull request. Also can we get some more Redbull?” &lt;/p&gt;
&lt;p&gt;I tried to skim for ideas around the office, but didn’t get very far. The hardest part was striking the right balance for my team. &lt;/p&gt;
&lt;p&gt;Last Christmas was a very tough time for the team, dealing with some very challenging things that came out of nowhere and kind of knocked the wind out of people. The team &lt;a href=&quot;https://twitter.com/adambrault/statuses/147852278928384000&quot;&gt;kept high spirits&lt;/a&gt;, but no doubt was it stressful. &lt;/p&gt;
&lt;p&gt;So I really wanted to do something special but not in an over the top, ostentatious way. I mean, Christmas is already a sore spot for some people, and I didn’t want to offend by any means possible. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/photo_9-2e4d3cb0eae6f9dc0561e1630816a893.jpg&quot; alt=&quot;an ampersand decorated with lights&quot;&gt;&lt;/p&gt;
&lt;p&gt;I decided to keep it ampersand themed. Handmade at times. Understated (mostly). Emphasis on creativity and thoughtfulness. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/photo_8-0d30d00ac91539a32d408ef17c9c39c6.jpg&quot; alt=&quot;cloud and ampersand felt ornaments hanging from a row of lights&quot;&gt;&lt;/p&gt;
&lt;p&gt;And truthfully, the decor doesn’t matter at all. It’s the spirit of the season and expressing that celebration of gratitude toward one another that’s what matters most. &lt;/p&gt;
&lt;p&gt;I feel so fortunate and like, inordinately blessed to work where I do with the people who I love, that having the opportunity to do something special like dream up little Christmas treats and scatter them all over our office – you know, when I put it that way, it sort of sounds like something that would happen at the office anyway. &lt;/p&gt;
&lt;p&gt;These people already embody Christmas for me everyday, so I was super hyperactivity levels of excited to do something that would make them smile or laugh. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/photo_6-4cbae577ded1f3afc541681ee6cac002.jpg&quot; alt=&quot;the kitchen list except everyone&amp;#x27;s pictures are on ornaments&quot;&gt;&lt;/p&gt;
&lt;p&gt;Anyway, I hope you enjoy our decorations and that you have the opportunity to do something to celebrate the ones you love this season. &lt;/p&gt;
&lt;p&gt;(Yes, I cut the clouds and ampersands out by hand. Thanks for the inspiration Amy!) &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/photo-0c6713e760f419b366e440a772d3aede.jpg&quot; alt=&quot;a christmas tree decorated with ampersands behind the &amp;#x26;yet logo&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[We had a team day]]></title><description><![CDATA[Sometime in the spring of this year, the &yet team caravanned down to the lovely southeastern Washington outpost of Walla Walla for a day of…]]></description><link>https://blog.andyet.com/2012/12/20/we-had-a-team-day/</link><guid isPermaLink="false">https://blog.andyet.com/2012/12/20/we-had-a-team-day/</guid><pubDate>Thu, 20 Dec 2012 15:34:44 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 510px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 32.450331125827816%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeUlEQVQY0zWRTU8TURSG5xf6C9ziHuPGHQtFTXRhiImyJuKCaEhJJRBjQRHM0JbW8lHazhTazkxn7sfcGaPRzeMpxcWTc+4975uck9ezucW6HFs67E+hkN7aeZWZKzP0wXOuDtdFZ9kKFCOb42RmbjU32plffJ4OIrJXNXR9gG4PSV/vSQ0xUYoTemHEl8Vdmve2CEcJd3zD8WFA+b5OJh5zndygWyFa9F5ebaPub6CWKugNH7VcRb3YIXn4AfOkynlzyP6DXb6vHJG3htw9SGmt1ykefyR9uo1e3SN9+Qm18hk7jPA6/Zju8YCxbBqPp1wOIsKza9TaN9Jah867FpVnX6ktVAgWNnnUNdQvY3R/wiiMCXpy4WTKqDdhnCi8k1ROUJbTzPJDel9oTA39RsDpJKMdJvhvmzTWmpzsXPDmLMNPDF1taWdmzsyTWhqxxiusoTAGJ+S31cnf/3CcBFb8Lsj/lLhfBX8lmHI2F53Sc8+MRGkyef8DDwCqfJMygxYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;andbang advent logo&quot;
        title=&quot;&quot;
        src=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
        srcset=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/29fe9/_Advent_Logo.png 151w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/6728c/_Advent_Logo.png 303w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png 510w&quot;
        sizes=&quot;(max-width: 510px) 100vw, 510px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sometime in the spring of this year, the &amp;#x26;yet team caravanned down to the lovely southeastern Washington outpost of Walla Walla for a day of team reflection, hanging out, and planning. It was a beautiful day and we took advantage by wandering around the Whitman College campus and talking about what we like about the team and ways to improve the team. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../uploads/teamday1.jpeg&quot; alt=&quot;the team sitting on some grass&quot;&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s now months later, and I was to have followed up long ago with a summary of actions we can take to be more awesome. I kept putting it off (not awesome) and recently got called out (awesome). Get with it Zanol. &lt;/p&gt;
&lt;p&gt;I had a chat with Adam Baldwin about where we&apos;re at today compared to what we got out of the team day. There are a few items that came out of that day, and, shockingly enough, we&apos;ve been working on those without specific prompting to &quot;follow up on team day.&quot; &lt;/p&gt;
&lt;p&gt;The part of me that started his career in a big corporate &quot;hey-we-care-about-all-the-things-you-say-and-here&apos;s-metrics-you-can-look-at-so-you-don&apos;t-give-management-a-bad-review&quot; environment feels pretty good about the fact that things just happen here. Seriously. Incredible. &lt;/p&gt;
&lt;p&gt;The things we found to be the biggest takeaways from that day, per team feedback were: &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Do better QA!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Be good to each other, always!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Communicate, communicate, communicate!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;better-qa&quot;&gt;&lt;a href=&quot;#better-qa&quot; aria-label=&quot;better qa permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Better QA&lt;/h3&gt;
&lt;p&gt;We have implemented many code quality controls, both technical (unit testing, linting) and process oriented (pull requests, etc) and developers are embracing them. This is fantastic and we will only continue to improve. And let&apos;s not forget the &lt;a href=&quot;http://andbang.com&quot;&gt;&amp;#x26;!&lt;/a&gt; team, who&apos;ve been making sure we always have quality code in production. Every day there are continual improvements in code quality, I can speak from experience: I&apos;ve recently started contributing to &amp;#x26;! and there are checks in place that make sure what goes into our company&apos;s product is worthy of carrying the &amp;#x26;yet name. &lt;/p&gt;
&lt;h3 id=&quot;be-good-to-each-other&quot;&gt;&lt;a href=&quot;#be-good-to-each-other&quot; aria-label=&quot;be good to each other permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Be Good To Each Other&lt;/h3&gt;
&lt;p&gt;I see a lot of support of each other within our team, even from our folks that aren&apos;t in our main office in Richland, WA. I have no doubt this will continue. This group is the single most supportive team I&apos;ve ever worked with. I don&apos;t think I&apos;d be alone in saying we&apos;re a second family to each other. &amp;#x3C;3 &lt;/p&gt;
&lt;h3 id=&quot;communicate&quot;&gt;&lt;a href=&quot;#communicate&quot; aria-label=&quot;communicate permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Communicate!&lt;/h3&gt;
&lt;p&gt;Adam Brault and Henrik Joreteg recently laid out a specific shipping plan for version 2.0 of our team collaboration tool &lt;a href=&quot;http://andbang.com&quot;&gt;AndBang (&amp;#x26;!)&lt;/a&gt; and the company as a whole. I think that&apos;s a big piece of what folks were looking for when they called communication out as an area that&apos;s important to them. &lt;/p&gt;
&lt;p&gt;We also started the &quot;email the team&quot; accountability when you&apos;re going to be somewhere other than your regular workplace at your regular time. It&apos;s all about expectations: we expect that our teammates are going to be there for us... unless they let us know, in which case we expect they&apos;re taking care of something else important in their lives. I can&apos;t impress enough how crucial it is to the team that all of us have time to take care of ourselves/our families. Paramount, yo. &lt;/p&gt;
&lt;p&gt;There&apos;s officially 18 of us. It&apos;s unreasonable to keep everyone on the same page, all day, everyday. So, that isn&apos;t our goal. Our goal is to keep everyone abreast of what&apos;s going on with the team in general and talk about things on the horizon pertinent to the whole team as much as we can. We&apos;ve got our weekly scrum on Mondays. We&apos;ve got &lt;a href=&quot;http://gingerhq.com&quot;&gt;Ginger&lt;/a&gt;, where we not only post what we did that day, but also semi-major announcements and discussions regularly. These are the tools we&apos;ve found to be useful, and in my mind they&apos;re that improvement we were looking for in communication. &lt;/p&gt;
&lt;p&gt;Communication is something that can always be worked on. It&apos;s very easy (and important!) to focus on the work and everyday happenings and leave the distribution of new information till later or till someone asks. Here&apos;s what this team expects: if you think something should be communicated to the whole team that hasn&apos;t been, you are accountable for finding out why it hasn&apos;t been. Sometimes &quot;it&quot; should be communicated, sometimes it shouldn&apos;t. If we all take personal responsibility for us all being in the loop, we&apos;re being the kind of team we want to be. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../uploads/teamday2.jpeg&quot; alt=&quot;the team sitting on some grass, henrik is wearing sunglasses&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;thats-it&quot;&gt;&lt;a href=&quot;#thats-it&quot; aria-label=&quot;thats it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;That&apos;s It&lt;/h3&gt;
&lt;p&gt;As it turns out, we&apos;ve already been doing the things we said we needed to do; without prompting. There&apos;s a couple new folks, and time has marched on, so I&apos;m sure things will continue to change and adapt to the needs of our team. &lt;/p&gt;
&lt;p&gt;The one core thing that I know will never change though, is that each and every one of the people on this team want this to be, and will continue to make it, the best team ever. &lt;/p&gt;
&lt;p&gt;Add your &lt;strong&gt;email&lt;/strong&gt; to join the &lt;strong&gt;And Bang 2.0 private beta invite&lt;/strong&gt; list:  &lt;/p&gt;</content:encoded></item><item><title><![CDATA[And Bang deploy process]]></title><description><![CDATA[Deploying a production application can be quite the chore. On the road to &! 2.0, our processes have changed significantly. In the beginning…]]></description><link>https://blog.andyet.com/2012/12/13/and-bang-deploy-process/</link><guid isPermaLink="false">https://blog.andyet.com/2012/12/13/and-bang-deploy-process/</guid><pubDate>Thu, 13 Dec 2012 11:08:50 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 510px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 32.450331125827816%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeUlEQVQY0zWRTU8TURSG5xf6C9ziHuPGHQtFTXRhiImyJuKCaEhJJRBjQRHM0JbW8lHazhTazkxn7sfcGaPRzeMpxcWTc+4975uck9ezucW6HFs67E+hkN7aeZWZKzP0wXOuDtdFZ9kKFCOb42RmbjU32plffJ4OIrJXNXR9gG4PSV/vSQ0xUYoTemHEl8Vdmve2CEcJd3zD8WFA+b5OJh5zndygWyFa9F5ebaPub6CWKugNH7VcRb3YIXn4AfOkynlzyP6DXb6vHJG3htw9SGmt1ykefyR9uo1e3SN9+Qm18hk7jPA6/Zju8YCxbBqPp1wOIsKza9TaN9Jah867FpVnX6ktVAgWNnnUNdQvY3R/wiiMCXpy4WTKqDdhnCi8k1ROUJbTzPJDel9oTA39RsDpJKMdJvhvmzTWmpzsXPDmLMNPDF1taWdmzsyTWhqxxiusoTAGJ+S31cnf/3CcBFb8Lsj/lLhfBX8lmHI2F53Sc8+MRGkyef8DDwCqfJMygxYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;andbang advent logo&quot;
        title=&quot;&quot;
        src=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
        srcset=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/29fe9/_Advent_Logo.png 151w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/6728c/_Advent_Logo.png 303w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png 510w&quot;
        sizes=&quot;(max-width: 510px) 100vw, 510px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deploying a production application can be quite the chore. On the road to &amp;#x26;! 2.0, our processes have changed significantly. In the beginning stages of &amp;#x26;! 1.0, I hate to say it, but deploys were a completely manual process. We logged in to the server over SSH, pulled from Git, and restarted processes all by hand. Less than ideal, to say the least. &lt;/p&gt;
&lt;p&gt;Managing those processes was just as bad; we were using forever and a simple SysVInit script (those things in /etc/init.d for you non-ops types) to run it. When the process would crash, forever would restart it and we&apos;d be happy. Everything seemed great, but then one day we accidentally pushed broken code live. What did forever do? Kept trying to help us, by restarting the process. The process that crashes instantly. Several CPU usage warning emails from our hosting provider later, we realized what had happened and fixed the broken code. That&apos;s when we realized that blindly restarting the app when it crashes wasn&apos;t a great idea. &lt;/p&gt;
&lt;p&gt;Since our servers all run Ubuntu, we already had Upstart in place so swapping out the old not-so-great init.d scripts for the new, much nicer, Upstart scripts was pretty simple and life was good again. With these we had a simple way to run the app under a different user (running as root is bad, please don&apos;t do it), load environment variables, and even respawn crashed processes (with limits! no more CPU usage warnings!). &lt;/p&gt;
&lt;p&gt;But alas, manually deploying code was still a problem. In came fabric. For &amp;#x26;! 1.0 we used a very simple fabric script that essentially did our manual deploy process for us. It performed all the same steps, in the same way, but the person deploying only had to run one command instead of several. That was good enough for quite some time. Until.. one day.. we needed to rollback to an old version of the app. But how? &lt;/p&gt;
&lt;p&gt;That instance required us to dig through commit logs to find the rollback point, and manually checkout the old version and restart processes. This, as you can guess, took some time. Time that the app was down. We knew that this was bad, but how could we solve it? Inspiration struck, and we modified the fabric script. So then when it deployed a new version of code, it first made a copy of the existing code and archived it with a timestamp. Then it would update the current code and restart the process. This meant that in order to rollback, all we would have to do is move the archive in place of the current code and restart the process. We patted ourselves on the back and merrily went back to work. &lt;/p&gt;
&lt;p&gt;Until, one day, we realized the app had once again stopped working. The cause? We overlooked how fast the drive on our server could fill up with us storing a full copy of the code every single time we deploy. A quick little modification to the script so that it kept only the last 10 archives and some manual file deletion, and we were back on track. &lt;/p&gt;
&lt;p&gt;Time went on, the deploy process continued to work, but much like every developer out there, we had dreams of making the process even more simple. Why did I have to push code, and then deploy it? Why couldn&apos;t a push to a specific branch deploy the code for me? Thus was born our next deploy process.. A small server to listen for Github web hooks. Someone pushes code, the server would see what branch it was pushed to, if it was the special branch &quot;deploy&quot; the server would run our fabric scripts for us. Success! Developers could now deploy to production without asking, just by pushing to the right branch! What could go wrong? &lt;/p&gt;
&lt;p&gt;As I&apos;m sure you guessed, the answer is a lot. People can accidentally push to the wrong branch, deploying their code unintentionally. Dependencies can change and fail to install in the fabric script. The fabric script could crash, and we would have no idea why. We had logs, of course, but the developers didn&apos;t have access to them. All they knew was they pushed code and it wasn&apos;t live. So we&apos;d poke around in the logs, find the problem, fix it, and go about our business grumbling to ourselves. This was also not going to work. &lt;/p&gt;
&lt;p&gt;After much deliberation, we went back to running a separate command to deploy to the live server. That way the git branches could be horribly broken, people could make mistakes, and we wouldn&apos;t end up bringing down the whole app. &lt;/p&gt;
&lt;p&gt;To help prevent broken code, we also changed our process for contribution. Instead of pushing code to master, developers are now asked to work in their own branch. When their code is complete, and tests pass, they then submit a pull request to have their code merged with master. This means that a second pair of eyes is on everything that goes in to master, and feedback can be given and heard before deploying code. &lt;/p&gt;
&lt;p&gt;To help enforce peer review, I wrote a very simple bot that monitors our pull requests and their comments in Github. Pull requests now require two votes (a +1 in the comments) before the &quot;merge&quot; button in the pull request will turn green. Until that happens, the button is gray. Although easy to override, when the button is gray a warning is displayed if it is pressed. This was a nice, neat, unobtrusive way of encouraging everyone to wait until their code has been reviewed before merging it into master and being deployed. &lt;/p&gt;
&lt;p&gt;While still not perfect, our methods have definitely matured. Every day we learn something new, and we strive to keep our methods working as cleanly and smoothly as possible. Regular discussions take place, and new ideas are always entertained. Some day, maybe we&apos;ll find the perfect way to deploy to production, but until we do we&apos;re having a lot of fun learning. &lt;/p&gt;
&lt;p&gt;Add your &lt;strong&gt;email&lt;/strong&gt; to join the &lt;strong&gt;And Bang 2.0 private beta invite&lt;/strong&gt; list:  &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Onboarding matters—kind of a lot]]></title><description><![CDATA[“Your onboarding sucks, guys.” In between bites of breakfast, our friend, Pradeep Elankumaran (Kicksend CEO), was giving us feedback on…]]></description><link>https://blog.andyet.com/2012/12/10/onboarding-matterskind-of-a-lot/</link><guid isPermaLink="false">https://blog.andyet.com/2012/12/10/onboarding-matterskind-of-a-lot/</guid><pubDate>Mon, 10 Dec 2012 18:01:08 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 510px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 32.450331125827816%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeUlEQVQY0zWRTU8TURSG5xf6C9ziHuPGHQtFTXRhiImyJuKCaEhJJRBjQRHM0JbW8lHazhTazkxn7sfcGaPRzeMpxcWTc+4975uck9ezucW6HFs67E+hkN7aeZWZKzP0wXOuDtdFZ9kKFCOb42RmbjU32plffJ4OIrJXNXR9gG4PSV/vSQ0xUYoTemHEl8Vdmve2CEcJd3zD8WFA+b5OJh5zndygWyFa9F5ebaPub6CWKugNH7VcRb3YIXn4AfOkynlzyP6DXb6vHJG3htw9SGmt1ykefyR9uo1e3SN9+Qm18hk7jPA6/Zju8YCxbBqPp1wOIsKza9TaN9Jah867FpVnX6ktVAgWNnnUNdQvY3R/wiiMCXpy4WTKqDdhnCi8k1ROUJbTzPJDel9oTA39RsDpJKMdJvhvmzTWmpzsXPDmLMNPDF1taWdmzsyTWhqxxiusoTAGJ+S31cnf/3CcBFb8Lsj/lLhfBX8lmHI2F53Sc8+MRGkyef8DDwCqfJMygxYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;andbang advent logo&quot;
        title=&quot;&quot;
        src=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
        srcset=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/29fe9/_Advent_Logo.png 151w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/6728c/_Advent_Logo.png 303w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png 510w&quot;
        sizes=&quot;(max-width: 510px) 100vw, 510px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;“Your onboarding sucks, guys.” &lt;/p&gt;
&lt;p&gt;In between bites of breakfast, our friend, &lt;a href=&quot;https://twitter.com/pradeep24&quot;&gt;Pradeep Elankumaran&lt;/a&gt; (&lt;a href=&quot;http://kicksend.com&quot;&gt;Kicksend&lt;/a&gt; CEO), was giving us feedback on using And Bang 1.0 right after the initial release. &lt;/p&gt;
&lt;p&gt;We got a lot of input in the early beta days of And Bang and had already made some iterations based on that feedback. But Pradeep was one of the few folks we’d sent an invite to without having some discussion about the app as they were using it for the first time. &lt;/p&gt;
&lt;p&gt;He quickly pointed out that we were almost certainly skewing the accuracy of our results by our involved presence when working with customers. So what did we do? &lt;/p&gt;
&lt;p&gt;The great thing about that conversation is Pradeep followed up his withering feedback with a full set of outstanding advice. &lt;/p&gt;
&lt;p&gt;“We made the same mistakes,” Pradeep said. “See, you guys know the app—but you have to learn to look at it from the perspective of a first-time user who doesn’t know and doesn’t care and isn’t going to give you more than a minute of their time.” &lt;/p&gt;
&lt;h3 id=&quot;anonymous-user-testing&quot;&gt;&lt;a href=&quot;#anonymous-user-testing&quot; aria-label=&quot;anonymous user testing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Anonymous user testing&lt;/h3&gt;
&lt;p&gt;The first thing we were going to need was a way to generate anonymous users on demand. I’d heard of &lt;a href=&quot;http://usertesting.com&quot;&gt;usertesting.com&lt;/a&gt; but hadn’t used it. Pradeep insisted we give it a try and said it had been a lot of help to them at Kicksend. &lt;/p&gt;
&lt;p&gt;In a very short time for a negligible fee, we had a dozen videos of people using (or completely failing to use) our app, along with their commentary. &lt;/p&gt;
&lt;p&gt;Watching those videos was eye-opening, embarassing, and encouraging—all at the same time. I remember Henrik and I looking at each other and saying sheepishly, “Well, the cool thing is we can fix all this!” &lt;/p&gt;
&lt;p&gt;As soon as we saw this feedback, we immediately had all kinds of very simple ideas for how we could improve the app for first-time users—the best being an interactive, scripted walkthrough of the app. &lt;/p&gt;
&lt;h3 id=&quot;metrics-with-user-funnels&quot;&gt;&lt;a href=&quot;#metrics-with-user-funnels&quot; aria-label=&quot;metrics with user funnels permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Metrics with user funnels&lt;/h3&gt;
&lt;p&gt;Pradeep asked if we were tracking user metrics. “Of course we’re tracking tons of metrics!” Were we using funnels? “What’s a funnel?” &lt;/p&gt;
&lt;p&gt;We were tracking user activity, but we weren’t doing it in a very useful way. &lt;/p&gt;
&lt;p&gt;We knew how many users had signed up, and had all kinds of details like how many were using the app, how much had been shipped, how many members per team, how many users were online. &lt;/p&gt;
&lt;p&gt;But, as Pradeep quickly pointed out, none of that is useful in understanding the story of an individual user. &lt;/p&gt;
&lt;p&gt;Pradeep pointed out, “You need to create funnels of the major milestones in turning someone from a prospect into a paying and happy customer, so you can see where you’re losing people.” &lt;/p&gt;
&lt;p&gt;SaaS metrics apps like &lt;a href=&quot;http://kissmetrics.com&quot;&gt;KISSMetrics&lt;/a&gt; and &lt;a href=&quot;http://mixpanel.com&quot;&gt;MixPanel&lt;/a&gt; allow you to create funnels to see how many customers you’re losing—and where. &lt;/p&gt;
&lt;p&gt;When we created a funnel, we saw that with each stage of our funnel, we were losing an increasing number of users in the early couple funnels. &lt;/p&gt;
&lt;p&gt;We saw that once a user had signed up, invited teammates, and they and their teammates had all performed the actions of the app, they stuck around long enough to truly trial it as a team, and from those, quite a decent number converted to paying customers. &lt;/p&gt;
&lt;p&gt;We believed our idea of a scripted walkthrough would improve the main problems we saw when watching the &lt;a href=&quot;http://usertesting.com&quot;&gt;usertesting.com&lt;/a&gt; videos—and now we had a way to measure its impact. &lt;/p&gt;
&lt;h3 id=&quot;an-interactive-walkthrough&quot;&gt;&lt;a href=&quot;#an-interactive-walkthrough&quot; aria-label=&quot;an interactive walkthrough permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;An interactive walkthrough&lt;/h3&gt;
&lt;p&gt;We had a screencast, but based on the results, it didn’t seem to do much good to orient people in the app. We believed that a forced, fun walkthrough of the app could be a great way to familiarize users and increase the likelihood they’d invite team members, who would also use the app. &lt;/p&gt;
&lt;p&gt;In executing an interactive tutorial of the app, we built a step-by-step “flying” animated overlay to take users through the key features of the app, constraining users’ interactions to the specific step we were asking them to complete. &lt;/p&gt;
&lt;p&gt;We didn’t want to be annoying, so we made it easy to exit, but something they could bring back just by clicking “help”. &lt;/p&gt;
&lt;p&gt;After deploying the new scripted walkthrough, right out of the gate we saw an improvement in the key problems we were trying to solve. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When combining a simple, one-minute, interactive walkthrough, we were able to increase the likelihood that a user who signed up would give the app a trial with their team—and we were able to determine this because of the funnel metrics we built.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Incidentally, our friends Max Cameron and Cameron West have since launched &lt;a href=&quot;http://kera.io&quot;&gt;kera.io&lt;/a&gt;, which aims to help very simple create walkthroughs of the sort that we originally built manually for And Bang 1.0. Highly recommended! &lt;/p&gt;
&lt;h3 id=&quot;tldr&quot;&gt;&lt;a href=&quot;#tldr&quot; aria-label=&quot;tldr permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;tl;dr&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Get advice from other folks who’ve built and iterated successful products and who will be blunt and honest with you. (Thanks, Pradeep!)&lt;/li&gt;
&lt;li&gt;Get anonymous user testing with a service like &lt;a href=&quot;http://usertesting.com&quot;&gt;usertesting.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Create and track user funnels using tools like &lt;a href=&quot;http://kissmetrics.com&quot;&gt;KISSMetrics&lt;/a&gt; and &lt;a href=&quot;http://mixpanel.com&quot;&gt;MixPanel&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Build an interactive walkthrough (instead of a screencast video) using a tool like &lt;a href=&quot;http://kera.io&quot;&gt;kera.io&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Add your &lt;strong&gt;email&lt;/strong&gt; to join the &lt;strong&gt;And Bang 2.0 private beta invite&lt;/strong&gt; list:  &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Lessons learned from 1.0 to 2.0 — Realtime]]></title><description><![CDATA[A big driver for And Bang was that it was all supposed to be "glowingly" realtime. Many apps that have some sort of "realtime" component…]]></description><link>https://blog.andyet.com/2012/12/07/lessons-learned-from-10-to-20-realtime/</link><guid isPermaLink="false">https://blog.andyet.com/2012/12/07/lessons-learned-from-10-to-20-realtime/</guid><pubDate>Fri, 07 Dec 2012 16:46:34 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 510px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 32.450331125827816%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeUlEQVQY0zWRTU8TURSG5xf6C9ziHuPGHQtFTXRhiImyJuKCaEhJJRBjQRHM0JbW8lHazhTazkxn7sfcGaPRzeMpxcWTc+4975uck9ezucW6HFs67E+hkN7aeZWZKzP0wXOuDtdFZ9kKFCOb42RmbjU32plffJ4OIrJXNXR9gG4PSV/vSQ0xUYoTemHEl8Vdmve2CEcJd3zD8WFA+b5OJh5zndygWyFa9F5ebaPub6CWKugNH7VcRb3YIXn4AfOkynlzyP6DXb6vHJG3htw9SGmt1ykefyR9uo1e3SN9+Qm18hk7jPA6/Zju8YCxbBqPp1wOIsKza9TaN9Jah867FpVnX6ktVAgWNnnUNdQvY3R/wiiMCXpy4WTKqDdhnCi8k1ROUJbTzPJDel9oTA39RsDpJKMdJvhvmzTWmpzsXPDmLMNPDF1taWdmzsyTWhqxxiusoTAGJ+S31cnf/3CcBFb8Lsj/lLhfBX8lmHI2F53Sc8+MRGkyef8DDwCqfJMygxYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;andbang advent logo&quot;
        title=&quot;&quot;
        src=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
        srcset=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/29fe9/_Advent_Logo.png 151w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/6728c/_Advent_Logo.png 303w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png 510w&quot;
        sizes=&quot;(max-width: 510px) 100vw, 510px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A big driver for And Bang was that it was all supposed to be &quot;glowingly&quot; realtime. Many apps that have some sort of &quot;realtime&quot; component have it sort of &quot;tacked-on&quot; to a more traditional request/response based infrastructure. We wanted the whole experience and the whole technology stack to be realtime.&lt;/p&gt;
&lt;p&gt;When I first started tinkering around with building a team task tool a few years ago, I grabbed a set of what were my familiar tools at the time. Django, MySQL and a bit of jQuery.&lt;/p&gt;
&lt;p&gt;As it turned out, if you want to build a highly interactive, multi-user, realtime application, Django or Rails and relational databases are not necessarily the right tools for the job.&lt;/p&gt;
&lt;p&gt;We quickly realized that we needed to find and learn, or create, a new set of tools to solve the types of problems this presented.&lt;/p&gt;
&lt;p&gt;You can trace our progress and experiments a bit by reading past blog posts on the process of finding or building those tools up until we finally launched 1.0 a year ago.&lt;/p&gt;
&lt;p&gt;When we launched at last year&apos;s Realtime Conference. We had something that worked. It worked really well, in fact. The amount of maintenance we&apos;ve had to do has been minimal and the tool has become a part of the daily workflow for quite a few happy customers.&lt;/p&gt;
&lt;p&gt;We accomplished our goal of making a highly synchronized, completely realtime app. Everything is synchronized. Even when you upload a new avatar your teammates will see it change live as soon as it&apos;s uploaded.&lt;/p&gt;
&lt;p&gt;Although we&apos;re proud of, and excited about, what we built for 1.0, something about it didn&apos;t feel quite right to us. As we went on to start building more features, we kept hitting roadblocks. For example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It wasn&apos;t very extensible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It was hard for people on our team to contribute to. The whole system was too complex and required too much knowledge of the whole stack in order to feel confident touching any of it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The server code and application data was very tightly coupled to the presentation of the data in the app.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In fact, in order to get this &quot;full stack eventing&quot; that we wanted, everything was quite tightly coupled.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It was difficult to visualize or manage the data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It was hard to build alternate interfaces or native apps.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, after doing some initial iterations on the launched 1.0 version we did some soul searching. We still didn&apos;t have this ideal realtime platform that we wanted. Being the nerds and tinkerers that we are, we went back to the drawing board.&lt;/p&gt;
&lt;h3 id=&quot;the-core-lesson&quot;&gt;&lt;a href=&quot;#the-core-lesson&quot; aria-label=&quot;the core lesson permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The core lesson&lt;/h3&gt;
&lt;p&gt;If I had to pick the biggest, most valuable lesson we learned from this whole experience, it is something that every computer science professor in the world could probably have told us:&lt;/p&gt;
&lt;p&gt;SEPARATION OF CONCERNS!&lt;/p&gt;
&lt;p&gt;Unless your goal is to build a completely decentralized system where each node is a server and a client I&apos;d suggest following a few simple rules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Servers are for data&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clients are for presentation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don&apos;t mix&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;divide-and-conquer&quot;&gt;&lt;a href=&quot;#divide-and-conquer&quot; aria-label=&quot;divide and conquer permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Divide and conquer&lt;/h3&gt;
&lt;p&gt;To illustrate my point, instead of &lt;em&gt;a single respository&lt;/em&gt; that contained &lt;em&gt;the entire&lt;/em&gt; AndBang 1.0 application. We now have the following codebases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;andbang-spec&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The single purpose of this repo is to describe the functionality of the API — in intense detail.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;accounts.andbang.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The application that does oauth and account managment. This is where you log in to manage the teams you&apos;re on, etc.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;api.andbang.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The API. It speaks nothing but data. It doesn&apos;t know even how to render HTML.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;docs.andbang.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&apos;s entire purpose is to document and demonstrate the API. And yet it doesn&apos;t actually contains any details about it. Instead it consumes a JSON spec that the API serves that describes its own capabilities. The docs app just renders it into a nice application you can use to explore the capabilities exposed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;andbang.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &quot;official&quot; desktop web client. But it&apos;s &lt;em&gt;just&lt;/em&gt; that, a client built on the public API. It doesn&apos;t contain any non-public information or get any special access. Any one of our customers will be capable of building something like this this without requesting any special access.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;andbang-iphone&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yup. Another &quot;official&quot; client. This time for iOS.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;andbang.js&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &quot;drop-in&quot; JS sdk that andbang.com uses to talk to the API. This is generated from consuming the andbang-spec.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;andbang-express-auth&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Drop in oauth middleware. If you happen to want to build an express.js app on our API. It makes the OAuth piece ridiculously simple.&lt;/p&gt;
&lt;p&gt;So, we went from a single repository that did everything. To &lt;em&gt;eight&lt;/em&gt; distinct codebases.&lt;/p&gt;
&lt;p&gt;We&apos;ll have a bunch of other posts that go into more detail about the various items above.&lt;/p&gt;
&lt;h3 id=&quot;why-this-matters&quot;&gt;&lt;a href=&quot;#why-this-matters&quot; aria-label=&quot;why this matters permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why this matters&lt;/h3&gt;
&lt;p&gt;Obviously, seperation of concerns is not a new concept by any means. However, when surveying the landscape of people who are wanting to build fully realtime apps I&apos;m seeing tight coupling of frontends to backends and interfaces to data structures.&lt;/p&gt;
&lt;p&gt;Ultimately, what we want is the ability to access our data lots of ways and to build a variety of interesting integrations and clients on it. The fact that it&apos;s also &quot;realtime&quot; shouldn&apos;t limit that.&lt;/p&gt;
&lt;p&gt;Frankly, in today&apos;s landscape with a plethora of client platforms building for only desktop web, or iOS, or Android, or tablets is silly. The most interesting services all provide this.&lt;/p&gt;
&lt;p&gt;If you want to be able to control your app from Google Glass or the HUD in your car, a tightly coupled desktop web app probably won&apos;t cut it.&lt;/p&gt;
&lt;p&gt;For more on all of this, see my talk from realtime conf:&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/52522287?badge=0&quot; height=&quot;281&quot; width=&quot;500&quot; allowfullscreen webkitallowfullscreen mozallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://vimeo.com/52522287&quot;&gt;RTC 2012 - 13 - Henrik Joreteg&lt;/a&gt; from &amp;#x26;&lt;a href=&quot;http://vimeo.com/andyet&quot;&gt;yet&lt;/a&gt; on &lt;a href=&quot;http://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Be sure to put yourself on the list for access to AndBang 2.0. Hope you like it!&lt;/p&gt;
&lt;p&gt;Add your &lt;strong&gt;email&lt;/strong&gt; to join the &lt;strong&gt;And Bang 2.0 private beta invite&lt;/strong&gt; list:&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Enabling contributions from team members]]></title><description><![CDATA[When I joined &yet this last January, &! (And Bang) 1.0 was already launched. A lot of the work had been done by one or two members of the…]]></description><link>https://blog.andyet.com/2012/12/04/enabling-contributions-from-team-members/</link><guid isPermaLink="false">https://blog.andyet.com/2012/12/04/enabling-contributions-from-team-members/</guid><pubDate>Tue, 04 Dec 2012 15:35:50 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 510px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 32.450331125827816%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeUlEQVQY0zWRTU8TURSG5xf6C9ziHuPGHQtFTXRhiImyJuKCaEhJJRBjQRHM0JbW8lHazhTazkxn7sfcGaPRzeMpxcWTc+4975uck9ezucW6HFs67E+hkN7aeZWZKzP0wXOuDtdFZ9kKFCOb42RmbjU32plffJ4OIrJXNXR9gG4PSV/vSQ0xUYoTemHEl8Vdmve2CEcJd3zD8WFA+b5OJh5zndygWyFa9F5ebaPub6CWKugNH7VcRb3YIXn4AfOkynlzyP6DXb6vHJG3htw9SGmt1ykefyR9uo1e3SN9+Qm18hk7jPA6/Zju8YCxbBqPp1wOIsKza9TaN9Jah867FpVnX6ktVAgWNnnUNdQvY3R/wiiMCXpy4WTKqDdhnCi8k1ROUJbTzPJDel9oTA39RsDpJKMdJvhvmzTWmpzsXPDmLMNPDF1taWdmzsyTWhqxxiusoTAGJ+S31cnf/3CcBFb8Lsj/lLhfBX8lmHI2F53Sc8+MRGkyef8DDwCqfJMygxYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;andbang advent logo&quot;
        title=&quot;&quot;
        src=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
        srcset=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/29fe9/_Advent_Logo.png 151w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/6728c/_Advent_Logo.png 303w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png 510w&quot;
        sizes=&quot;(max-width: 510px) 100vw, 510px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When I joined &amp;#x26;yet this last January, &amp;#x26;! (And Bang) 1.0 was already launched. A lot of the work had been done by one or two members of the &amp;#x26;yet team. &lt;/p&gt;
&lt;p&gt;But, And Bang was a product of the company, not just a couple of people, so we had to find a way to better enable contributions from the rest of the team. Its core ideas were us—so &lt;em&gt;very&lt;/em&gt; us—so why shouldn’t more of the team be enabled to contribute on a significant level? &lt;/p&gt;
&lt;p&gt;Significantly increasing the number of contributors is more difficult than you might imagine. I pushed very hard to empower team members to contribute as much as possible. These efforts paid off, the team was energized to help but we also learned a few thing along the way. &lt;/p&gt;
&lt;p&gt;For starters, we did simple things that had a huge impact. We developed a set of general standards for code that we could enforce. We used jshint and passing test cases as a roadblock to get code into the project. &lt;/p&gt;
&lt;p&gt;We also added a github inspired pull request flow as a code review step. These few steps serve as a gateway for getting code into the project. However, by the time you send a pull request you&apos;ve already built what you think that feature or fix should be. &lt;/p&gt;
&lt;p&gt;Engineers see problems very differently from one to the next and thus, come up with drastically different solutions. Some just &quot;make it go&quot; and some really optimize to the nth degree. To improve this and spare misguided work we adjusted our issue tracking process. &lt;/p&gt;
&lt;p&gt;We broke out tasks and features into smaller issues in Github and gave free-for-all access to help build And Bang. &lt;/p&gt;
&lt;p&gt;We quickly had a lot of the team contributing at an amazing pace. &lt;/p&gt;
&lt;p&gt;During this time we had one major interruption that all but killed enablement of our team to contribute: we refactored all the things. &lt;/p&gt;
&lt;p&gt;This refactor was again completed by the small core team that was curating the features and design of the product. The scope of these changes temporarily blocked others from contributing. While frustrating at the time and while it felt like a black cloud looming over the project it ultimately had a positive impact in enabling contributions from others. &lt;/p&gt;
&lt;p&gt;The core of the refactoring involved decoupling the API from the client and writing a spec that strictly defined the API. This allowed us to use it as a gauge of completeness of the implementation. Now the API could be designed as a separate step, and our team was free to implement to that spec. &lt;/p&gt;
&lt;p&gt;In addition this specification allows for interactive documentation to be always up to date and automated testing of all aspects of the API to a much deeper level than before. This means that developers know if they broke something immediately as the tests are run during every commit. &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/27b7ae0b1668aa4dd366f548be9a5c63/0abdd/andbang_docs.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 510px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 61.58940397350994%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAACiklEQVQozz1Sy04bQRDcPyGKX3efIpHAP+SUBFmAjbGTA/J3RPmmXHKJggIY2xDY9T7xrr3v2feaQ6VnTGKp1dO945rqrpK63S4ODw+xv/8WB/tv0Hr3HnsfvuL1p294dfARncYeWu0Omq0W2u02Wi+50+n8D95rNptoNBqQzodDTC4uMB6PMZlMMDo/x5hi2B9gOBhgNBrh7GwAfu/L57HI/X4fJycnOD4+xunpKY6OjtDr9URPSvISU82B7QYIgwBFUUKxfSwsD6rtocwzOAHD3HRxb7lYrkNEcQLbduB5AYIghOt6SJIU/Cf5vo/r6S1kRaFLNqIowv2fBzzICnTDhO97It/OFpjezvGoLBHHDIZhgbEUZbklEjXyvKJzDakoCiRxRB9juhgjTRIkdE4pGNUJ1WnCRO9f1PUW67WL1cqB42xE5DRpVW0h5WUF2ycwopym/MUSbpTCiwgoTVDSg3FaYBNTj2XwKFdVDV03YVkrMXZRVCIEoBdEuFzIUDQDpmGInfyaPWAua9A0TTCfP6r4/vMKPy5vcH2voCRAx14jDGNkWS5GLfIXwJyWzsUIw5DAArEf33MRUe1TzRij0Z6wlGUs+Z5XK2y3z/Q9hqbq0IlIlhW0hucdYF1z9IxGy4WiFY3Mx6yo5o9xBnVVYVtXlEvRF4ARg0IC2cSUK853yseWfLLAtfKEme5QrLEOGe7ofEU9dbUhgEzY57dsYU79hblBRqryP/M9GhRcbc5yt0OyzXQ2h0ofNNNCEEa4I9vckEVkYsCF0XRD1Cpl88kWohSk6lJRiaVKayJnJNmOIbfNzh7cGkwozffGa24jft5Zib1ETCJU2Gw8BH4oRg9IWC4Qt85f4T05+CBl2ckAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;andbang docs&quot;
        title=&quot;&quot;
        src=&quot;/static/27b7ae0b1668aa4dd366f548be9a5c63/0abdd/andbang_docs.png&quot;
        srcset=&quot;/static/27b7ae0b1668aa4dd366f548be9a5c63/29fe9/andbang_docs.png 151w,
/static/27b7ae0b1668aa4dd366f548be9a5c63/6728c/andbang_docs.png 303w,
/static/27b7ae0b1668aa4dd366f548be9a5c63/0abdd/andbang_docs.png 510w&quot;
        sizes=&quot;(max-width: 510px) 100vw, 510px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I think it&apos;s important to evaluate the efforts of the fast-moving prototypers in terms of the resulting impact on others ability to contribute. Also, to be aware of the &quot;wake&quot; that this creates and communicate that to the team so as not to discourage those trying to help. This may manifest itself as un-mergable pull requests which represent wasted time and effort. &lt;/p&gt;
&lt;p&gt;Issues now go through a workflow that is similar to &lt;/p&gt;
&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/4bac2fb41e117fd384cf79c11acd4f2e/6af66/andbang_process.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 74.8344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC/0lEQVQozx2SS3PjRBSF9WdZZYpK8Iwdy5Zaz35JarVaar3dsS3bsRwyKQ+pTAhTE8hAICxYMBsexX9BUHXq7k6d+917tPSNVbniIlSbbL+vbjp5uOm+/XB8Pu4e9otjV1139c26evvx9pfPL3///vNf766ejtefPr7/7eWHP7VyairIN/GiLy77Yl+Roomavjlsyo0SF9tyu84363z7+O775/vn+6vvvl7fHvvHh29efv30h1bPzHWQXqbrvrzsy20TVZEdMicUKAHnNjQxtcNGqG2935Z9V+63dX99+PHu/vPT0z+aMpwtK/u8O5S7vtotU9Xypk3aWrQiKqpMtfmySVVX7XbNZVdsunxzWN0erx4fbn7SktFUYbGOmxVvu3x1kSkZ5U22yNNWDjNXMmtV3S0HinxdRE3D2oW4WMrubv9BQydfxTM/scPYDmtWJDgBuu0A5COOgxQSDlzC46LIFmWmQphxKAI7jFx+073X+EiXFhF2KDyWESGjjEeSMelABhDDPGeyjdM6y+pSLiVrBM6KoGzixfXqVmsMV5FEhUVFZU5TTgVGnIYZDAWgCUxKKqpYNplsq2yxGKBormK1r3bDRzVlukualD6vSCqJiCBHkLkotmliBakTScSLQFQibXJel6yMXbaI6l2+eru80xodtF6QABwDEgDiG9AyfMNCuo2nNjV8ZhPuU0Fw5lmBN4N4jiUSS95eFf1Qknnl4MylQ1ZgYmQg10QWQKZDgEMH8uFmhKYhzbETwhmCOow91gbFXu60fDIrbJI6AbdoaGI89+Ec+gB7NvWcAPqMYB7ilBOZkiz1k2HtgshV3PZyq+XjaekQ6TIOaDDYpo49BmAM7KnrGwjbAXUi5sahFTGbsf/Ll8O0JXkXKa2azhuXlB5LAfVfG+cno/npZPrleHY2dc4tX/fwHKIZNF8b45OxNTL8ieOMQDRDChVaOzcb2ysBSuaeezoZf/HKeDUCp2N3pPsT4z+NgTcB5pluneneG4PqfjT1M4MoP/kXHLwBBy0c5woAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;andbang issue workflow&quot;
        title=&quot;&quot;
        src=&quot;/static/4bac2fb41e117fd384cf79c11acd4f2e/90cbd/andbang_process.png&quot;
        srcset=&quot;/static/4bac2fb41e117fd384cf79c11acd4f2e/29fe9/andbang_process.png 151w,
/static/4bac2fb41e117fd384cf79c11acd4f2e/6728c/andbang_process.png 303w,
/static/4bac2fb41e117fd384cf79c11acd4f2e/90cbd/andbang_process.png 605w,
/static/4bac2fb41e117fd384cf79c11acd4f2e/6af66/andbang_process.png 640w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Issue is reported. If that issue is a feature request it’s scrubbed by the curators of the app. &lt;/p&gt;
&lt;p&gt;If it’s a bug we try and put as much design decision into the ticket as possible or via discussions, then it’s on to implementation, polish, tire-kicking, pull request, review, approval and finally the glorious pushing to production. &lt;/p&gt;
&lt;p&gt;At this point we can fire on all cylinders and be confident on what is working, as well as what doesn’t work. People can contribute in their area of expertise whether that is API, client side, design, whatever without fearing breaking things they don&apos;t understand. &lt;/p&gt;
&lt;p&gt;The best part about all of this? We aren’t done improving. Software development is very much like a mobius strip. You come back to where you started, having learned a lot more from the trip. We&apos;re just sharing what we&apos;ve learned so far. &lt;/p&gt;
&lt;p&gt;Add your &lt;strong&gt;email&lt;/strong&gt; to join the &lt;strong&gt;And Bang 2.0 private beta invite&lt;/strong&gt; list:  &lt;/p&gt;</content:encoded></item><item><title><![CDATA[The history of And Bang]]></title><description><![CDATA[At &yet, we’ve used a lot of different project management tools for our work building web software for human people.If you’re like us, it’s…]]></description><link>https://blog.andyet.com/2012/12/03/the-history-of-and-bang/</link><guid isPermaLink="false">https://blog.andyet.com/2012/12/03/the-history-of-and-bang/</guid><pubDate>Mon, 03 Dec 2012 17:47:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo_1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 510px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 32.450331125827816%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeUlEQVQY0zWRTU8TURSG5xf6C9ziHuPGHQtFTXRhiImyJuKCaEhJJRBjQRHM0JbW8lHazhTazkxn7sfcGaPRzeMpxcWTc+4975uck9ezucW6HFs67E+hkN7aeZWZKzP0wXOuDtdFZ9kKFCOb42RmbjU32plffJ4OIrJXNXR9gG4PSV/vSQ0xUYoTemHEl8Vdmve2CEcJd3zD8WFA+b5OJh5zndygWyFa9F5ebaPub6CWKugNH7VcRb3YIXn4AfOkynlzyP6DXb6vHJG3htw9SGmt1ykefyR9uo1e3SN9+Qm18hk7jPA6/Zju8YCxbBqPp1wOIsKza9TaN9Jah867FpVnX6ktVAgWNnnUNdQvY3R/wiiMCXpy4WTKqDdhnCi8k1ROUJbTzPJDel9oTA39RsDpJKMdJvhvmzTWmpzsXPDmLMNPDF1taWdmzsyTWhqxxiusoTAGJ+S31cnf/3CcBFb8Lsj/lLhfBX8lmHI2F53Sc8+MRGkyef8DDwCqfJMygxYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;andbang advent logo&quot;
        title=&quot;&quot;
        src=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo_1.png&quot;
        srcset=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/29fe9/_Advent_Logo_1.png 151w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/6728c/_Advent_Logo_1.png 303w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo_1.png 510w&quot;
        sizes=&quot;(max-width: 510px) 100vw, 510px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet, we’ve used a lot of different project management tools for our work building web software for human people.&lt;/p&gt;
&lt;p&gt;If you’re like us, it’s always hard to find one collaboration tool that “fits” and really helps you get things done. One day we realized: &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Project management tools are primarily great at &lt;em&gt;managing things you’re going to do later&lt;/em&gt;. They’re &lt;em&gt;planning&lt;/em&gt; tools, not &lt;em&gt;doing&lt;/em&gt; tools. To manage the work you&apos;re &lt;em&gt;doing&lt;/em&gt;, you need completely different tools.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Personally, when I’ve used project management tools like Basecamp or issue management tools like FogBugz and GitHub Issues, I’ve often felt overwhelmed about the size and guilty about what’s still broken or left to do. I always get distracted and it seems like there’s a significant amount of busy work associated with maintaining the right workflow for the most trivial things, which makes me unfairly frustrated with the tool. &lt;/p&gt;
&lt;p&gt;That’s not a good mental state for me to work from—and you probably feel the same way. &lt;/p&gt;
&lt;p&gt;So we said, “Let’s strip away all of the future-looking tools from our daily workflow and focus on right now.” &lt;/p&gt;
&lt;p&gt;We’re big believers in using the right tool for the job—in our software, in our communication, and planning. We don’t do much without asking things like, “why are we doing it this way?” and “is this really the &lt;em&gt;best&lt;/em&gt; approach?” (This makes me especially pleased to work with some of my favorite people to argue with, by the way. The productive disagreements we’ve had over big-picture and fine-grained details have repeatedly proven valuable.) &lt;/p&gt;
&lt;p&gt;So when we discovered that most of the tools we considered for focusing on “now” were inadequately bloated for that specific task, we decided to throw away all our tools and go to a paper process that looked like this: &lt;/p&gt;
&lt;p&gt;Each person would write the work they needed to actually &lt;em&gt;finish&lt;/em&gt; on Post-It notes—all clearly measurable as to whether the item was &quot;done&quot; or not and at whatever granularity was useful for communication to team members. We put the notes up on a grid with our names. Whichever items we were working on at the moment, we would just take off grid and stick them to our doors as a way of indicating what we were working on. &lt;/p&gt;
&lt;p&gt;We found it to be more effective and straightforward than any method we used to date. It worked with whatever other software our team used for bug-tracking and backlogging. And it was completely flexible. &lt;/p&gt;
&lt;p&gt;Except for one thing—sometimes we didn&apos;t work from the office. We needed to take the same simple approach and put it online. &lt;/p&gt;
&lt;p&gt;So that&apos;s what we did with And Bang. &lt;/p&gt;
&lt;h3 id=&quot;so-lets-talk-about-and-bang&quot;&gt;&lt;a href=&quot;#so-lets-talk-about-and-bang&quot; aria-label=&quot;so lets talk about and bang permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So let&apos;s talk about And Bang.&lt;/h3&gt;
&lt;p&gt;It’s so hard to finish things, isn&apos;t it? &lt;/p&gt;
&lt;p&gt;And it&apos;s just as hard to stay on the same page with your team. I find it to be a constant Catch-22: how do you balance your desire to not interrupt your teammates with your need to know? &lt;/p&gt;
&lt;p&gt;Checkins and stand-ups and scrums are fine, but sometimes they&apos;re not necessary, sometimes schedules don&apos;t align, and I know I always feel like I suddenly remember most of what I needed to communicate 30 minutes after we&apos;re done meeting. &lt;/p&gt;
&lt;p&gt;Call another meeting? Send an email or IM? Poke your head in? None of those options are awesome. &lt;/p&gt;
&lt;p&gt;It&apos;s frustrating—and the tragedy is that it&apos;s always simple stuff that gets in the way. “Are you going to fix that bug today?” “Did you review that email?” “Wait, you haven&apos;t started that yet?” “Oh, you didn’t even catch that I was asking you to do that?” “What? You&apos;re already finished?” &lt;/p&gt;
&lt;p&gt;With And Bang, we stripped everything down to the basics: “What are you working on right now?” and “What does your short list look like?” &lt;/p&gt;
&lt;p&gt;Then, for additional communication, we added notifications when a team member has finished something, plus the ability to chat together as a team. &lt;/p&gt;
&lt;h3 id=&quot;what-about-and-bang-20&quot;&gt;&lt;a href=&quot;#what-about-and-bang-20&quot; aria-label=&quot;what about and bang 20 permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What about And Bang 2.0?&lt;/h3&gt;
&lt;p&gt;In building And Bang 2.0, we listened carefully to our customers and stayed focused on the core of the simple product they love. &lt;/p&gt;
&lt;p&gt;We very strongly didn’t want to go overboard and unintentionally make a simple product more overwhelming by adding a huge number of features and complexity. If anything, we wanted to make things simpler and clearer. &lt;/p&gt;
&lt;p&gt;We’ve focused on turning And Bang from a simple tool into a simple tool and powerful platform, extending its reach, dramatically increasing its power and flexibility, and unlocking an immense amount of potential for integration into all the other tools you already use to get your work done and communicate. &lt;/p&gt;
&lt;h3 id=&quot;sign-up-for-the-chance-to-get-an-early-beta-invite&quot;&gt;&lt;a href=&quot;#sign-up-for-the-chance-to-get-an-early-beta-invite&quot; aria-label=&quot;sign up for the chance to get an early beta invite permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sign up for the chance to get an early beta invite&lt;/h3&gt;
&lt;p&gt;We’re excited to share And Bang 2.0 with you soon and this month we plan on sharing a ton of what we&apos;ve learned in building it. &lt;/p&gt;
&lt;p&gt;We’ll be giving away some beta invites later this month to folks who sign up, so add your email to be one of the first to try And Bang 2.0. &lt;/p&gt;
&lt;p&gt;Add your &lt;strong&gt;email&lt;/strong&gt; to join the &lt;strong&gt;And Bang 2.0 private beta invite&lt;/strong&gt; list:  &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Introducing And Bang Advent 2012]]></title><description><![CDATA[The development of our favorite teamwork tool, And Bang, has had such a significant impact on our company’s trajectory that we wanted to…]]></description><link>https://blog.andyet.com/2012/12/03/introducing-and-bang-advent-2012/</link><guid isPermaLink="false">https://blog.andyet.com/2012/12/03/introducing-and-bang-advent-2012/</guid><pubDate>Mon, 03 Dec 2012 17:42:51 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 510px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 32.450331125827816%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeUlEQVQY0zWRTU8TURSG5xf6C9ziHuPGHQtFTXRhiImyJuKCaEhJJRBjQRHM0JbW8lHazhTazkxn7sfcGaPRzeMpxcWTc+4975uck9ezucW6HFs67E+hkN7aeZWZKzP0wXOuDtdFZ9kKFCOb42RmbjU32plffJ4OIrJXNXR9gG4PSV/vSQ0xUYoTemHEl8Vdmve2CEcJd3zD8WFA+b5OJh5zndygWyFa9F5ebaPub6CWKugNH7VcRb3YIXn4AfOkynlzyP6DXb6vHJG3htw9SGmt1ykefyR9uo1e3SN9+Qm18hk7jPA6/Zju8YCxbBqPp1wOIsKza9TaN9Jah867FpVnX6ktVAgWNnnUNdQvY3R/wiiMCXpy4WTKqDdhnCi8k1ROUJbTzPJDel9oTA39RsDpJKMdJvhvmzTWmpzsXPDmLMNPDF1taWdmzsyTWhqxxiusoTAGJ+S31cnf/3CcBFb8Lsj/lLhfBX8lmHI2F53Sc8+MRGkyef8DDwCqfJMygxYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;andbang advent logo&quot;
        title=&quot;&quot;
        src=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png&quot;
        srcset=&quot;/static/3a6de7754d0bd9bc4cd4b73981da3852/29fe9/_Advent_Logo.png 151w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/6728c/_Advent_Logo.png 303w,
/static/3a6de7754d0bd9bc4cd4b73981da3852/0abdd/_Advent_Logo.png 510w&quot;
        sizes=&quot;(max-width: 510px) 100vw, 510px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The development of our favorite teamwork tool, And Bang, has had such a significant impact on our company’s trajectory that we wanted to take some time out during this holiday season to share some of what we&apos;ve learned with our community and fellow And Bang users.&lt;/p&gt;
&lt;p&gt;This December, we’re rolling out the first ever And Bang Advent. &lt;/p&gt;
&lt;p&gt;We’ll highlight different perspectives and pieces of the puzzle that we’ve delightfully (and/or painfully) come across during our journey from And Bang 1.0+ to the mysterious 1.5 that we never shipped, to our present work pushing to ship And Bang 2.0. &lt;/p&gt;
&lt;p&gt;It’s been reflecting on this path and recounting our experiences which makes us so genuinely excited to share with you what’s in store for And Bang 2.0. &lt;/p&gt;
&lt;p&gt;So please join us over the next few weeks as we reflect on our lessons learned and count down to the next chapter of And Bang! Follow &lt;a href=&quot;http://twitter.com/andbang&quot;&gt;@andbang&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; and we&apos;ll keep you in the loop. &lt;/p&gt;
&lt;p&gt;Also! As a concluding piece of our holiday series, we’ll be sharing a few beta invites of And Bang 2.0. You can sign up right here. &lt;/p&gt;
&lt;p&gt;Add your &lt;strong&gt;email&lt;/strong&gt; to join the &lt;strong&gt;And Bang 2.0 private beta invite&lt;/strong&gt; list:  &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Realtime—what is it?]]></title><description><![CDATA[Whenever there is discussion on this topic, there's always someone who asks, "What is realtime?"The answer, as it turns out, has several…]]></description><link>https://blog.andyet.com/2012/09/28/realtimewhat-is-it/</link><guid isPermaLink="false">https://blog.andyet.com/2012/09/28/realtimewhat-is-it/</guid><pubDate>Fri, 28 Sep 2012 10:44:44 GMT</pubDate><content:encoded>&lt;p&gt;Whenever there is discussion on this topic, there&apos;s always someone who asks, &quot;What is realtime?&quot;&lt;/p&gt;
&lt;p&gt;The answer, as it turns out, has several layers.&lt;/p&gt;
&lt;p&gt;On the surface, realtime is about websites which dynamically update from outside data sources without user intervention.&lt;/p&gt;
&lt;p&gt;This sounds rather uninteresting to many, as this has been done since the days of Yahoo! Chat in 1994, but there is more to it than that.&lt;/p&gt;
&lt;p&gt;To get into the meat of it, we need to ask, &quot;When is realtime useful in a web application?&quot;&lt;/p&gt;
&lt;p&gt;Ok, so...&lt;/p&gt;
&lt;h3 id=&quot;when-is-realtime-useful-in-a-web-application&quot;&gt;&lt;a href=&quot;#when-is-realtime-useful-in-a-web-application&quot; aria-label=&quot;when is realtime useful in a web application permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;When is realtime useful in a web application?&lt;/h3&gt;
&lt;p&gt;Realtime data driven applications are only useful when you are aggregating data from multiple sources.&lt;/p&gt;
&lt;p&gt;Think about it; think about a shopping cart, for example. You could make a single-page shopping-cart application that does all sorts of AJAX updates, but it&apos;s not realtime because you&apos;re the only input.&lt;/p&gt;
&lt;p&gt;Why have the server send you data when you didn&apos;t take an action when you&apos;re a customer adding things to a shopping-cart and checking out? A dashboard where an administrator can see live stats (or aggregated and batched stat updates) as the users make purchases would certainly be realtime. The fact that there are multiple sources of data aggregated by the server-application or client-application in addition to live-updating is what makes it realtime. The administrator might be able to deliver special offers specifically to individuals or groups of people he sees making purchases to upsell them and suddenly the user side of the application is realtime as well, because an extra source of data has been added (the administrator&apos;s user-focused upsell promotions).&lt;/p&gt;
&lt;h3 id=&quot;what-methods-can-you-use-for-realtime-web-applications&quot;&gt;&lt;a href=&quot;#what-methods-can-you-use-for-realtime-web-applications&quot; aria-label=&quot;what methods can you use for realtime web applications permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What methods can you use for realtime web applications?&lt;/h3&gt;
&lt;p&gt;To qualify as realtime, it really doesn&apos;t matter what method you&apos;re using to get data to the web-client.&lt;/p&gt;
&lt;p&gt;Websockets, long-polling, jsonp, out-of-band, timed Ajax requests, or whatever you come up with can all work fine.&lt;/p&gt;
&lt;p&gt;However, it&apos;s certainly worth discussing best-practices, developing new techniques, and sharing our experiences with realtime, because it&apos;s hard and the results are valuable.&lt;/p&gt;
&lt;p&gt;That&apos;s why we&apos;ve put together the &lt;a href=&quot;http://2012.realtimeconf.com&quot;&gt;Realtime Conference&lt;/a&gt;, as a way to make these things better and form a community around many technologies.&lt;/p&gt;
&lt;h3 id=&quot;what-are-some-of-the-challenges-unique-to-realtime-web-applications&quot;&gt;&lt;a href=&quot;#what-are-some-of-the-challenges-unique-to-realtime-web-applications&quot; aria-label=&quot;what are some of the challenges unique to realtime web applications permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What are some of the challenges unique to realtime web applications?&lt;/h3&gt;
&lt;p&gt;The short answer is scaling, synchronizing, and UI.&lt;/p&gt;
&lt;p&gt;The scaling problems with realtime, which vary depending on your approach, are unique.&lt;/p&gt;
&lt;p&gt;If you use websockets, you&apos;re going to use more RAM on the servers (holding open each stateful connection), have to deal with reconnecting sessions, and other complexities, but it may mean your servers take less of a CPU pounding than Ajax polling, for example.&lt;/p&gt;
&lt;p&gt;Synchronizing client state must be very methodical and architected carefully.&lt;/p&gt;
&lt;p&gt;Getting clients out of sync between client and server or even javascript and DOM can happen if you&apos;re not careful.&lt;/p&gt;
&lt;p&gt;Client-side MVC (backbone/spine/ember.js anyone?) can help ease some of this pain, but you still have to deal with caching.&lt;/p&gt;
&lt;p&gt;If the client can&apos;t deal well with the raw amount of data it has, it needs to be able to throw some away (treating your local copy as a cache because the server is usually the authority for your data).&lt;/p&gt;
&lt;p&gt;Oh, and don&apos;t forget to think about what happens when the user is disconnected and takes actions during that time.&lt;/p&gt;
&lt;p&gt;Realtime UIs that look cool may be hard to use because you are affecting the user&apos;s interface while they&apos;re potentially using it.&lt;/p&gt;
&lt;p&gt;Take the time to think about how to get new information to a user in such a way that doesn&apos;t interrupt them, which pieces of information is actually useful, and whether you want to to strictly control user views from the server.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Realtime web applications aggregate multiple sources of data (users, servers, sensors, whatever) and present them or hint at updates to an web user. It&apos;s a subtle and hard thing to get just right, and there are many evolving approaches.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://2012.realtimeconf.com&quot;&gt;The Realtime Conference&lt;/a&gt; is all about exploring, discussing, and bringing minds together to evolve and create better ways to make our applications use live data to interact with our users. You should come! We&apos;ve just added &lt;a href=&quot;https://tito.io/&amp;#x26;yet/realtime-2012&quot;&gt;a few more tickets&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/KRT-promo.png&quot; alt=&quot;krtconf promo&quot;&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/RedisConf-promo.png&quot; alt=&quot;redisconf promo&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Hipsters on Realtime 2]]></title><description><![CDATA[We asked Portlandians about realtime technologies—and, um, they answered!DISCLAIMER: No hipsters feelings were harmed in the making of this…]]></description><link>https://blog.andyet.com/2012/09/24/hipsters-on-realtime-2/</link><guid isPermaLink="false">https://blog.andyet.com/2012/09/24/hipsters-on-realtime-2/</guid><pubDate>Mon, 24 Sep 2012 16:48:58 GMT</pubDate><content:encoded>&lt;iframe src=&quot;https://player.vimeo.com/video/50102770&quot; height=&quot;287&quot; width=&quot;510&quot; allowfullscreen webkitallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;We asked Portlandians about realtime technologies—and, um, they answered!&lt;/p&gt;
&lt;p&gt;DISCLAIMER: No hipsters feelings were harmed in the making of this video.&lt;/p&gt;
&lt;p&gt;Film by Miss Melanie Brown&lt;br&gt;
Music by &lt;a href=&quot;teamyacht.com&quot;&gt;YACHT&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you enjoyed this, be sure to check out &lt;a href=&quot;https://vimeo.com/28516402&quot;&gt;last year&apos;s video&lt;/a&gt;, too. :)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/KRT-promo.png&quot; alt=&quot;krtconf promo&quot;&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/RedisConf-promo.png&quot; alt=&quot;redisconf promo&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[We’re keeping it “Realtime Conference”]]></title><description><![CDATA[Yeah, that’s correct. We’re changing the name of our conference on realtime technologies.(Who does that? I dunno. Uhhh, I guess: “us”?) But…]]></description><link>https://blog.andyet.com/2012/09/23/were-keeping-it-realtime-conference/</link><guid isPermaLink="false">https://blog.andyet.com/2012/09/23/were-keeping-it-realtime-conference/</guid><pubDate>Sun, 23 Sep 2012 20:38:23 GMT</pubDate><content:encoded>&lt;p&gt;Yeah, that’s correct. We’re changing the name of &lt;a href=&quot;http://2012.realtimeconf.com&quot;&gt;our conference on realtime technologies&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;(Who does that? I dunno. Uhhh, I guess: “us”?) But—more importantly—&lt;strong&gt;why?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We got a few good chuckles from folks from the name &quot;The Keeping it Realtime Conference&quot; But, we&apos;ve gotta be honest: it&apos;s a really long mouthful, and people who want to talk about it get confused with how to shorten it into an abbreviated mouthful—oh, and then!—people who read “krtconf” have no idea what the heck the conference is actually about.&lt;/p&gt;
&lt;p&gt;Basically, it’s a fun name, but we’d rather have something that people just “get”.&lt;/p&gt;
&lt;p&gt;So, hereafter, The Keeping it Realtime Conference will now be called “The Realtime Conference”—or “RealtimeConf” for short.&lt;/p&gt;
&lt;p&gt;Oh, also?&lt;/p&gt;
&lt;p&gt;This year&apos;s &lt;a href=&quot;&quot;&gt;Realtime Conference&lt;/a&gt; is going to be the best thing that &amp;#x26;yet has ever shipped. We have worked so hard on it.&lt;/p&gt;
&lt;p&gt;We&apos;re so excited to pair it up with the first ever &lt;a href=&quot;http://redisconf.com&quot;&gt;RedisConf&lt;/a&gt; the day before, and an awesome &lt;a href=&quot;http://redisconf.com/training&quot;&gt;Redis Master Class&lt;/a&gt;, too.&lt;/p&gt;
&lt;p&gt;Tickets are &lt;a href=&quot;https://tito.io/&amp;#x26;yet/redisconf&quot;&gt;on sale now for RedisConf and Redis Training&lt;/a&gt;. They&apos;re currently &lt;strong&gt;sold out for RealtimeConf&lt;/strong&gt;—but we&apos;ll be adding a few more before the event, so &lt;a href=&quot;https://tito.io/&amp;#x26;yet/realtime-2012&quot;&gt;add your name to the waitlist&lt;/a&gt; and we&apos;ll keep you posted.&lt;/p&gt;
&lt;p&gt;Follow &lt;a href=&quot;http://twitter.com/realtimeconf&quot;&gt;@RealtimeConf&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/twitter.com/RedisConf&quot;&gt;@RedisConf&lt;/a&gt; on Twitter for the latest updates. We have a ton more speaker announcements we&apos;ll be making shortly!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/KRT-promo.png&quot; alt=&quot;krtconf promo&quot;&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/RedisConf-promo.png&quot; alt=&quot;redisconf promo&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Stop sending template engines to the browser! A retrospectively obvious way to create templates that are 6-10 times faster.]]></title><description><![CDATA[These days, more and more HTML is rendered on the client instead of sent pre-rendered by the server. So If you're building a web app that…]]></description><link>https://blog.andyet.com/2012/09/13/stop-sending-template-engines-to-the-browser-a-ret/</link><guid isPermaLink="false">https://blog.andyet.com/2012/09/13/stop-sending-template-engines-to-the-browser-a-ret/</guid><pubDate>Thu, 13 Sep 2012 15:14:34 GMT</pubDate><content:encoded>&lt;p&gt;These days, more and more HTML is rendered on the client instead of sent pre-rendered by the server. So If you&apos;re building a web app that uses a lot of client side javascript you&apos;ll doubtlessly want to create some HTML in the browser.&lt;/p&gt;
&lt;h3 id=&quot;how-we-used-to-do-it&quot;&gt;&lt;a href=&quot;#how-we-used-to-do-it&quot; aria-label=&quot;how we used to do it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How we used to do it&lt;/h3&gt;
&lt;p&gt;First a bit of history. When I first wrote &lt;a href=&quot;http://icanhazjs.com&quot;&gt;ICanHaz.js&lt;/a&gt; I was just trying to ease a pain point I was having: generating a bunch of HTML in a browser is a pain.&lt;/p&gt;
&lt;p&gt;Why is it a pain? Primarily because JS doesn&apos;t cleanly support multi-line strings, but also because there isn&apos;t an awesome string interpolation system built into JS.&lt;/p&gt;
&lt;p&gt;To work around that, ICanHaz.js, as lots of other template clientside template systems do, uses a hack to make it easier to send arbitrary strings to the browser. As it turns out, browsers ignore content in &lt;code class=&quot;language-text&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags if you give them a &lt;code class=&quot;language-text&quot;&gt;type&lt;/code&gt; attribute that isn&apos;t &lt;code class=&quot;language-text&quot;&gt;text/javascript&lt;/code&gt;. So, ICanHaz reads the content of tags on the page that say: &lt;code class=&quot;language-text&quot;&gt;&amp;lt;script type=“text/html”&amp;gt;&lt;/code&gt; which can contain templates or any other multi-line strings for that matter. So, ICanHaz will reads those templates and turns each of them into a function that you can call to render that string with your data mixed into it. For example:&lt;/p&gt;
&lt;p&gt;This html:
&lt;br&gt;
&lt;br&gt;
&lt;script id=&quot;user&quot; type=&quot;text/html&quot;&gt;
&lt;li&gt;
&lt;p class=&quot;name&quot;&gt;Hello I&apos;m {{ name }}&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://twitter.com/{{ twitter }}&quot;&gt;@{{ twitter }}&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/script&gt;
&lt;/p&gt;
&lt;p&gt;Is read by ICanHaz and turned into a function you call with your own like this:
&lt;br&gt;
&lt;br&gt;
// your data
var data = {
first&lt;em&gt;name: &quot;Henrik&quot;,
last&lt;/em&gt;name: &quot;Joreteg&quot;
}
&lt;br&gt;
// I can has user??
html = ich.user(data)
&lt;/p&gt;
&lt;p&gt;This works, and lots of people clearly thought the same as it&apos;s been quite a popular library.&lt;/p&gt;
&lt;h3 id=&quot;why-thats-less-than-ideal&quot;&gt;&lt;a href=&quot;#why-thats-less-than-ideal&quot; aria-label=&quot;why thats less than ideal permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why that&apos;s less-than-ideal&lt;/h3&gt;
&lt;p&gt;It totally works, but if you think about it, it&apos;s a bit silly. It&apos;s not super fast and you&apos;re making the client do a bunch of extra parsing just to turn text into a function. You also have to send the entire template engine to the browser which is a bunch of wasted bandwidth.&lt;/p&gt;
&lt;h3 id=&quot;how-were-doing-it-now&quot;&gt;&lt;a href=&quot;#how-were-doing-it-now&quot; aria-label=&quot;how were doing it now permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How we&apos;re doing it now&lt;/h3&gt;
&lt;p&gt;What I finally realized is that all you actually want when doing templating on the client is the end result that ICanHaz gives you: a function that you call with your data that returns your HTML.&lt;/p&gt;
&lt;p&gt;Typically, smart template engines, like the newer versions of Mustache.js, do this for you. Once the template has been read, it gets compiled into a function that is cached and used for subsequent rending of that same template.&lt;/p&gt;
&lt;p&gt;Thinking about this leaves me asking: why don&apos;t we just send the javascript template function to the client instead of doing all the template parsing/compiling on the client?&lt;/p&gt;
&lt;p&gt;Well, frankly, because I didn&apos;t really know of a great way to do it. &lt;/p&gt;
&lt;p&gt;I started looking around and realized that &lt;a href=&quot;http://jade-lang.com&quot;&gt;Jade&lt;/a&gt; (which we already use quite a bit at &amp;#x26;yet) has support for compiling as a separate process and, in combination with a small little runtime snippet, this lets you create JS functions that don&apos;t need the whole template engine to render. Which is totally awesome!&lt;/p&gt;
&lt;p&gt;So, to make it easier to work with, I wrote a little tool: &lt;a href=&quot;http://github.com/henrikjoreteg/templatizer&quot;&gt;templatizer&lt;/a&gt; that you can run on the server-side (using node.js) to take a folder full of jade templates and turn them into a javascript file that you can include in your app that has just has the template rendering functions as javascript.&lt;/p&gt;
&lt;h3 id=&quot;the-end-result&quot;&gt;&lt;a href=&quot;#the-end-result&quot; aria-label=&quot;the end result permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The end result&lt;/h3&gt;
&lt;p&gt;From my tests the actual rendering of templates is &lt;strong&gt;6 to 10 times faster&lt;/strong&gt;. In addition you&apos;re sending &lt;em&gt;way&lt;/em&gt; less code to the browser (because you&apos;re not sending a whole templating engine) and you&apos;re not making the browser do a bunch of work you could have already done ahead of time.&lt;/p&gt;
&lt;p&gt;I still need to write more docs and use it for a few more projects before we have supreme confidence in it, but I&apos;ve been quite happy with the results so far and wanted to share it. &lt;/p&gt;
&lt;p&gt;I&apos;d love to hear your thoughts. I&apos;m &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; on twitter and you should follow &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; as well and check out our awesome team same-pagification tool &lt;a href=&quot;http://andbang.com&quot;&gt;And Bang&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See you on the Internet. Go build awesome stuff!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/KRT-promo.png&quot; alt=&quot;krtconf promo&quot;&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/RedisConf-promo.png&quot; alt=&quot;redisconf promo&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[&yet talks with Panic founders Cabel Sasser and Steven Frank]]></title><description><![CDATA[The joy of independent software is that some of the most successful people also happen to be some of the most generous, friendly, and…]]></description><link>https://blog.andyet.com/2012/09/11/yet-talks-with-panic-founders-cabel-sasser-and-ste/</link><guid isPermaLink="false">https://blog.andyet.com/2012/09/11/yet-talks-with-panic-founders-cabel-sasser-and-ste/</guid><pubDate>Tue, 11 Sep 2012 10:27:37 GMT</pubDate><content:encoded>&lt;iframe src=&quot;https://player.vimeo.com/video/49200659&quot; height=&quot;287&quot; width=&quot;510&quot; allowfullscreen webkitallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;The joy of independent software is that some of the most successful people also happen to be some of the most generous, friendly, and fascinating.&lt;/p&gt;
&lt;p&gt;We feel lucky to have been invited in to Panic&apos;s headquarters to interview founders Cabel Sasser and Steven Frank. We loved what they had to say about shipping, building a business, being a team, and leadership.&lt;/p&gt;
&lt;p&gt;Just like their products, these two guys have immense character--in both senses of the word.&lt;/p&gt;
&lt;p&gt;Thanks so much, Cabel and Steven!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/KRT-promo.png&quot; alt=&quot;krtconf promo&quot;&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/RedisConf-promo.png&quot; alt=&quot;redisconf promo&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Cleanliness in clientside JS]]></title><description><![CDATA[The single biggest challenge you'll have when building complex clientside application is keeping your code base from becoming a garbled pile…]]></description><link>https://blog.andyet.com/2012/09/07/cleanliness-in-clientside-js/</link><guid isPermaLink="false">https://blog.andyet.com/2012/09/07/cleanliness-in-clientside-js/</guid><pubDate>Fri, 07 Sep 2012 15:12:02 GMT</pubDate><content:encoded>&lt;p&gt;The single biggest challenge you&apos;ll have when building complex clientside application is keeping your code base from becoming a garbled pile of mess.&lt;/p&gt;
&lt;p&gt;If it&apos;s a longer running project that you plan on maintaining and changing over time, it&apos;s even harder. Features come and go. You&apos;ll experiment with something only to find it&apos;s not the right call. &lt;/p&gt;
&lt;p&gt;I write lots of single page apps and I absolutely &lt;em&gt;despise&lt;/em&gt; messy code. Here are a few techniques, crutches, coping mechanisms, and semi-pro tips for staying sane.&lt;/p&gt;
&lt;h3 id=&quot;separating-views-and-state&quot;&gt;&lt;a href=&quot;#separating-views-and-state&quot; aria-label=&quot;separating views and state permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Separating views and state&lt;/h3&gt;
&lt;p&gt;This is the biggest lesson I&apos;ve learned building lots of single page apps. Your view (the DOM) should just be blind slave to the model state of your application. For this you could use any number of tools and frameworks. I&apos;d recommend starting with &lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt; (by the awesome Mr. &lt;a href=&quot;https://twitter.com/jashkenas&quot;&gt;@jashkenas&lt;/a&gt; as it&apos;s the easiest to understand, IMO. &lt;/p&gt;
&lt;p&gt;Essentially, you&apos;ll build up a set of models and collections in memory in the browser. These models should be completely oblivious to how they&apos;re used. Then you have views that listen for changes in the models and update the DOM. This could be a whole giant blog post in an of itself. But this core principal of separating your views and your application state is vital when building large apps.&lt;/p&gt;
&lt;h3 id=&quot;common-js-modules&quot;&gt;&lt;a href=&quot;#common-js-modules&quot; aria-label=&quot;common js modules permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Common JS Modules&lt;/h3&gt;
&lt;p&gt;I&apos;m not going to get into a debate about module styles and script loaders. But I can tell you this: I haven&apos;t seen any cleaner, simpler mechanism for splitting your code into nice isolated chunks than Common JS modules.&lt;/p&gt;
&lt;p&gt;It&apos;s the same style/concept that is used in node.js. By following this style I get the additional benefit of being able to re-use modules written for the client on the server and vice versa.&lt;/p&gt;
&lt;p&gt;If you&apos;re unfamiliar with the Common JS modules style, your files end up looking something like this:
&lt;br&gt;
&lt;br&gt;
// you import things by using the special &lt;code class=&quot;language-text&quot;&gt;require&lt;/code&gt; function and you can
// assign the result to a variable
&lt;br&gt;
var StrictModel = require(&apos;strictModel&apos;),
_ = require(&apos;underscore&apos;);
&lt;br&gt;
// you expose functionality to other modules by declaring your main export
// like this.
module.exports = StrictModel.extend({
type: &apos;navItem&apos;,
props: {
active: [&apos;boolean&apos;, true, false],
url: [&apos;string&apos;, true, &apos;&apos;],
position: [&apos;number&apos;, true, 200]
},
init: function () {
// some, something
}
});
&lt;/p&gt;
&lt;p&gt;Of course, browsers don&apos;t have support for these kinds of modules out of the box (there is no &lt;code class=&quot;language-text&quot;&gt;window.require&lt;/code&gt;). But, luckily that can be fixed. I use a clever little tool called &lt;a href=&quot;https://github.com/sstephenson/stitch&quot;&gt;stitch&lt;/a&gt; written by &lt;a href=&quot;https://twitter.com/sstephenson&quot;&gt;Sam Stephenson&lt;/a&gt; of 37signals. There&apos;s also another one by &lt;a href=&quot;https://twitter.com/substack&quot;&gt;@substack&lt;/a&gt; called &lt;a href=&quot;https://github.com/substack/node-browserify&quot;&gt;browserify&lt;/a&gt; that lets you use a lot of the node.js utils on the client as well.&lt;/p&gt;
&lt;p&gt;What they do is create a &lt;code class=&quot;language-text&quot;&gt;require&lt;/code&gt; function and bundle up a folder of modules into an app package.&lt;/p&gt;
&lt;p&gt;Stitch is written for node.js but you could just as easily just use another server-side language and just use node to build your client package. Ultimately it&apos;s just creating a single JS file and of course at that point you can just serve it like any other static file.&lt;/p&gt;
&lt;p&gt;You set up Stitch in a simple express server like this:
&lt;br&gt;
&lt;br&gt;
// require express and stitch
var express = require(&apos;express&apos;),
stitch = require(&apos;stitch&apos;);
&lt;br&gt;
// define our stitch package
var appPackage = stitch.createPackage({
// you add the folders whose contents you want to be “require-able”
paths: [
__dirname + &apos;/clientmodules&apos;,  // this is where i put my standalone modules
__dirname + &apos;/clientapp&apos; // this is where i put my modules that compose the app
],
// you can also include normal dependencies that are not written in the
// commonJS style
dependencies: [
somepath + &apos;/jquery.js&apos;,
somepath + &apos;/bootstrap.js&apos;
]
});
&lt;br&gt;
// init express
var app = express.createServer();
&lt;br&gt;
// define a path where you want your JS package to be server
app.get(&apos;/myAwesomeApp.js&apos;, appPackage.createServer());
&lt;br&gt;
// start listening for requests
app.listen(3000);
&lt;/p&gt;
&lt;p&gt;At this point you can just go to &lt;code class=&quot;language-text&quot;&gt;http://localhost:3000/myAwesomeApp.js&lt;/code&gt; in a browser and you should see your whole JS package.&lt;/p&gt;
&lt;p&gt;This is handy while developing because you don&apos;t have to re-start or recompile anything when you make changes to the files in your package.&lt;/p&gt;
&lt;p&gt;Once you&apos;re ready to go to production you can use the package and uglify JS to write a minified file to disk to be served staticly:
&lt;br&gt;
&lt;br&gt;
var uglifyjs = require(&apos;uglify-js&apos;),
fs = require(&apos;fs&apos;);
&lt;br&gt;
function uglify(code) {
var ast = uglifyjs.parser.parse(code);
ast = uglifyjs.uglify.ast&lt;em&gt;mangle(ast);
ast = uglifyjs.uglify.ast&lt;/em&gt;squeeze(ast);
return uglifyjs.uglify.gen_code(ast);
}
&lt;br&gt;
// assuming &lt;code class=&quot;language-text&quot;&gt;appPackage&lt;/code&gt; is in scope of course, this is just a demo
appPackage.compile(function (err, source) {
fs.writeFileSync(&apos;build/myAwesomeApp.js&apos;, uglify(source));
});
&lt;/p&gt;
&lt;h3 id=&quot;objection-its-a-huge-single-file-thats-going-to-load-slow&quot;&gt;&lt;a href=&quot;#objection-its-a-huge-single-file-thats-going-to-load-slow&quot; aria-label=&quot;objection its a huge single file thats going to load slow permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Objection! It&apos;s a huge single file, that&apos;s going to load slow!&lt;/h3&gt;
&lt;p&gt;Two things. Don&apos;t write a huge app with loads and loads of giant dependencies. Second, cache it! If you do your job right, your users will only download that file once and you can probably do it while they&apos;re not even paying attention. If you&apos;re clever you can even prime their cache by lazy-loading the app on the login screen, or some other such cleverness.&lt;/p&gt;
&lt;p&gt;Not to mention, for single page apps, speed once your app has loaded is much more important than the time it takes to do the initial load.&lt;/p&gt;
&lt;h3 id=&quot;code-linting&quot;&gt;&lt;a href=&quot;#code-linting&quot; aria-label=&quot;code linting permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Code Linting&lt;/h3&gt;
&lt;p&gt;If you&apos;re building large JS apps and not doing some form of static analysis on your code, you&apos;re asking for trouble. It helps catch silly errors and forces code style consistency. Ideally, no one should be able to tell who wrote what part of your app. If you&apos;re on a team, it should all be uniform within a project. How do you do that? We use a slick tool written by &lt;a href=&quot;https://twitter.com/quitlahok&quot;&gt;Nathan LaFreniere&lt;/a&gt; on our team called, simply, &lt;a href=&quot;https://github.com/nathan-lafreniere/precommit-hook&quot;&gt;precommit-hook&lt;/a&gt;. So all we have to do is:
&lt;br&gt;
&lt;br&gt;
npm install precommit-hook
&lt;/p&gt;
&lt;p&gt;What that will do is create a git pre-commit hook that uses JSHint to check your project for code style consistency before each commit. Once upon a time there was a tool called JSLint written by Mr. Crockford. Nowadays (love that silly word) there&apos;s a less strict, more configurable version of the same project called &lt;a href=&quot;http://www.jshint.com/&quot;&gt;JSHint&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;The neat thing about the npm version of JSHint is that if you run it from the command line it will look for a configuation file (.jshintrc) and an ignore file (.jshintignore) both of which the precommit hook will create for you if they don&apos;t exist. You can use these files to configure JSHint to follow the code style rules that you&apos;ve defined for the project. This means that you can now run &lt;code class=&quot;language-text&quot;&gt;jshint .&lt;/code&gt; at the root of your project and lint the entire thing to make sure it follows the code styles you&apos;ve defined in the &lt;code class=&quot;language-text&quot;&gt;.jshintrc&lt;/code&gt; file. Awesome, right!?!&lt;/p&gt;
&lt;p&gt;Our &lt;code class=&quot;language-text&quot;&gt;.jshintrc&lt;/code&gt; files usually looks something like this:
&lt;br&gt;
&lt;br&gt;
{
&quot;asi&quot;: false,
&quot;expr&quot;: true,
&quot;loopfunc&quot;: true,
&quot;curly&quot;: false,
&quot;evil&quot;: true,
&quot;white&quot;: true,
“undef&quot;: true,
&quot;predef&quot;: [
&quot;app&quot;,
&quot;$&quot;,
&quot;require&quot;,
&quot;__dirname&quot;,
&quot;process&quot;,
&quot;exports&quot;,
&quot;module&quot;
]
}
&lt;/p&gt;
&lt;p&gt;The awesome thing about this approach is that you can enforce consistency and that the rules for the project are contained and actually checked into the project repo itself. So if you decide to have a different set of rules for the next project, fine. It&apos;s not a global setting it&apos;s defined and set by whomever runs the project.&lt;/p&gt;
&lt;h3 id=&quot;creating-an-app-global&quot;&gt;&lt;a href=&quot;#creating-an-app-global&quot; aria-label=&quot;creating an app global permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Creating an &quot;app&quot; global&lt;/h3&gt;
&lt;p&gt;So what makes a module? Ideally, I&apos;d suggest each module being in it&apos;s own file and only exporting one piece of functionality. Only having a single export helps you keep clear what purpose the module has and keeps it focused on just that task. The goal is having lots of modules that do one thing really well and then your app just combines modules into a coherent story.&lt;/p&gt;
&lt;p&gt;When I&apos;m building an app, I intentionally have one main controller object of sorts. It&apos;s attached to the window as “app” just for my own. For modules that I&apos;ve written specifically for this app (stuff that&apos;s in the clientapp folder) I allow myself the use of that global to perform app-level actions like navigating, etc. &lt;/p&gt;
&lt;h3 id=&quot;using-events-modules-talking-to-modules&quot;&gt;&lt;a href=&quot;#using-events-modules-talking-to-modules&quot; aria-label=&quot;using events modules talking to modules permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Using events: Modules talking to modules&lt;/h3&gt;
&lt;p&gt;How do you keep your modules cleanly separated? Sometimes modules are dependant on other modules. How do you keep them loosely coupled? One good technique is triggering lots of events that can be used as hooks by other code. Many of the core components in node.js are extensions of EventEmitter the reason is that you can register handlers for stuff that happens to those items just like you can register a handler for someone clicking a link in the browser. This pattern is really useful when building re-usable compenents yourself. By exporting things that inherit from event emitters means that the code using your module can specify what they care about rather than the module having to know. For example, see the super simplified version of the And Bang js library below.&lt;/p&gt;
&lt;p&gt;There are lots of implementations of event emitters. We use a modified version of one from the LearnBoost guys: &lt;a href=&quot;https://twitter.com/tjholowaychuk&quot;&gt;@tjholowaychuk&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/rauchg&quot;&gt;@rauchg&lt;/a&gt; and company. It&apos;s &lt;a href=&quot;https://github.com/HenrikJoreteg/wildemitter&quot;&gt;wildemitter&lt;/a&gt; on my github if you&apos;re curious. But the same concept works for any of the available emitters. See below:
&lt;br&gt;
&lt;br&gt;
// require our emitter
var Emitter = require(&apos;wildemitter&apos;);
&lt;br&gt;
// Our main constructor function
var AndBang = function (config) {
// extend with emitter
Emitter.call(this);
};
&lt;br&gt;
// inherit from emitter
AndBang.prototype = new Emitter();
&lt;br&gt;
// Other methods
AndBang.prototype.setName = function (newName) {
this.name = newName;
// we can trigger arbitrary events
// these are just hooks that other
// code could chose to listen to.
this.emit(&apos;nameChanged&apos;, newName);
};
&lt;br&gt;
// export it to the world
module.exports = AndBang;
&lt;/p&gt;
&lt;p&gt;Then, other code that wants to use this module can listen for events like so:
&lt;br&gt;
&lt;br&gt;
var AndBang = require(&apos;andbang&apos;),
api = new AndBang();
&lt;br&gt;
// now this handler will get called any time the event gets triggered
api.on(&apos;nameChanged&apos;,  function (newName) { /* do something cool */ });
&lt;/p&gt;
&lt;p&gt;This pattern makes it easy to expose functionality without having to know anything about the consuming code.&lt;/p&gt;
&lt;h3 id=&quot;more&quot;&gt;&lt;a href=&quot;#more&quot; aria-label=&quot;more permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;More?&lt;/h3&gt;
&lt;p&gt;I&apos;m tired of typing so that&apos;s all for now. :)&lt;/p&gt;
&lt;p&gt;But I just thought I&apos;d share some of the tools, techniques and knowledge we&apos;ve acquired through blood, sweat and mistakes. If you found it helpful, useful or if you want to yell at me. You can follow me on twitter: &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;See ya on the interwebs! Build cool stuff!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/KRT-promo.png&quot; alt=&quot;krtconf promo&quot;&gt;&lt;img src=&quot;https://dl.dropbox.com/u/10292774/RedisConf-promo.png&quot; alt=&quot;redisconf promo&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Adam Baldwin will share his xss.io toolkit in his talk at DEFCON 20]]></title><description><![CDATA[This week is the 20th anniversary of one of the worlds largest and longest running hacker conferences, DEFCON.&yet Security Officer Adam…]]></description><link>https://blog.andyet.com/2012/07/26/adam-baldwin-will-share-his-xssio-toolkit-in-his-t/</link><guid isPermaLink="false">https://blog.andyet.com/2012/07/26/adam-baldwin-will-share-his-xssio-toolkit-in-his-t/</guid><pubDate>Thu, 26 Jul 2012 05:24:26 GMT</pubDate><content:encoded>&lt;p&gt;This week is the 20th anniversary of one of the worlds largest and longest running hacker conferences, &lt;a href=&quot;http://defcon.org&quot;&gt;DEFCON&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;#x26;yet Security Officer Adam Baldwin will be presenting Friday at 5:30 PM on “Blind XSS (cross-site scripting)”. &lt;/p&gt;
&lt;p&gt;Adam’s talk will announce the release and demonstrate the &lt;a href=&quot;http://xss.io&quot;&gt;xss.io toolkit&lt;/a&gt;. xss.io is a platform to help ease cross-site scripting (xss) exploitation. We use this tool to to demonstrate to our clients the severity and exploitability of vulnerabilities we find in their web applications. &lt;/p&gt;
&lt;p&gt;Adam will also announce [redacted] during the talk, which will also aid in the exploitation of web applications. &lt;/p&gt;
&lt;p&gt;Should you be at DEFCON and want to corner Adam to chat, you can find &lt;/p&gt;
&lt;p&gt;him Thursday night supporting the EFF at the &lt;a href=&quot;http://twitter.com/effsummit&quot;&gt;@effsummit&lt;/a&gt;. You can also &lt;/p&gt;
&lt;p&gt;find him &lt;a href=&quot;http://twitter.com/adam_baldwin&quot;&gt;on twitter&lt;/a&gt;. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Context and the future ultimate gadget]]></title><description><![CDATA[Futurists tend to see gadgets and computers as assistants to our lives, but they're still just tools. I think we're close, we just need to…]]></description><link>https://blog.andyet.com/2012/07/08/context-and-the-future-ultimate-gadget/</link><guid isPermaLink="false">https://blog.andyet.com/2012/07/08/context-and-the-future-ultimate-gadget/</guid><pubDate>Sun, 08 Jul 2012 23:41:52 GMT</pubDate><content:encoded>&lt;p&gt;Futurists tend to see gadgets and computers as assistants to our lives, but they&apos;re still just tools. I think we&apos;re close, we just need to combine some technologies that already exist and add a little context.&lt;/p&gt;
&lt;p&gt;But what&apos;s really the problem?&lt;/p&gt;
&lt;h3 id=&quot;the-problem&quot;&gt;&lt;a href=&quot;#the-problem&quot; aria-label=&quot;the problem permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Problem&lt;/h3&gt;
&lt;p&gt;Here we are, in the future, and boy is it overwhelming. I have a phone with several hundred &quot;apps&quot;, about 400 websites I care about, a desktop at home and a laptop for work, a tablet, and maybe someday I&apos;ll have some Google glasses. Do I need all of this? Probably not, but it makes for some easy context. I use each device for different purposes, but what if my devices were more aware of what I was doing?&lt;/p&gt;
&lt;h3 id=&quot;one-gadget-to-rule-them-all&quot;&gt;&lt;a href=&quot;#one-gadget-to-rule-them-all&quot; aria-label=&quot;one gadget to rule them all permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;One Gadget to Rule Them All&lt;/h3&gt;
&lt;p&gt;I imagine it won&apos;t be too long before the number of devices we have is cut down, especially when something the size of a watch will be more than enough power to do most of what I need to do, even if we can&apos;t yet imagine what the interfaces will be- but there are hints. My Android phone has a Car Mode. When I dock my phone in in my car, a new UI comes up that gives me only the things that I&apos;ll care about in a car.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://f.cl.ly/items/2N1g3D1p3Y020R1U0I3s/car_mode.png&quot; alt=&quot;Android Car Mode&quot;&gt; Android Car Mode&lt;/p&gt;
&lt;p&gt;The Cius concept tablet by Cisco is another great example. The device can present different UIs and prompt different apps based on whether it is plugged into your office phone dock or not.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://f.cl.ly/items/2F3L2g000z0W3o2B040K/Cisco-Cius-Tablet-Review.jpg&quot; alt=&quot;Cisco Cius&quot;&gt; Cisco Cius&lt;/p&gt;
&lt;p&gt;But we can do better than just docks and plugs. Our phones, increasingly, know where we are with alarming accuracy. Your phone knows what networks you&apos;re near, probably know the ambient temperature, could check noise levels, and all sorts of other things. All of these things could hint at context.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://f.cl.ly/items/0f0d032Y0k1x3q33373o/0_21_iphone_heat_warning.jpg&quot; alt=&quot;iPhone Heat&quot;&gt; iPhone Heat&lt;/p&gt;
&lt;h3 id=&quot;contexts-like-what&quot;&gt;&lt;a href=&quot;#contexts-like-what&quot; aria-label=&quot;contexts like what permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Contexts… like What?&lt;/h3&gt;
&lt;p&gt;Our phone should try to use this information to make an educated guess at what we&apos;re up or where we&apos;re at. Are we in the kitchen? Great, let&apos;s promote memos, todos, and shopping list, and recipe apps and webpages. Let&apos;s show a family-calendar widget. Maybe it should do a quick check to see we might have expired food from the last shopping trip.&lt;/p&gt;
&lt;p&gt;Another context could be the livingroom or den, where we&apos;ll promote tv listing bookmarks, our remote control app, and other apps and webpages that we or the app/page author have tagged as #living/den.&lt;/p&gt;
&lt;p&gt;Ok, now I&apos;m at work. On this context, I&apos;ve put my work calendar widget, email, task managers, and quick search for contacts. Oh wait, it&apos;s kind of echoey in here, wireless conectivity strength went down a bit, maybe we&apos;re in the office bathroom; time for games and email - hold my calls, please.&lt;/p&gt;
&lt;p&gt;Back at my desk, I plug my phone into my dock, and now it&apos;s my work computer, complete with screen, keyboard, and mouse, and if I want to work in the lobby to get a bit of sunshine, I&apos;ll plug it into my clamshell laptop. In these contexts, my phone acts like a PC, and effectively is one.&lt;/p&gt;
&lt;h3 id=&quot;how-are-they-managed&quot;&gt;&lt;a href=&quot;#how-are-they-managed&quot; aria-label=&quot;how are they managed permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How Are they Managed?&lt;/h3&gt;
&lt;p&gt;But what if my phone guesses the wrong context, or I want to play a game while I&apos;m in the kitchen waiting for the oven to pre-heat? No problem, just manually switch contexts just like you&apos;d manually switch to an app folder.&lt;/p&gt;
&lt;p&gt;End users should be able to easily make their own context, edit existing ones, and share them with friends and co-workers. If I download a shared context, and I don&apos;t have some of the widgets and apps listed, I can substitute my own, or click on the placeholders to go to the market or app store to buy and download it.&lt;/p&gt;
&lt;p&gt;More advanced context authors should be able to completely skin the interface and tweak the sensor hinting settings to provide a highly customized and accurate experience. App and webapp authors as well as app stores will enjoy that users are essentially recommending apps and services to eachother by sharing these contexts.&lt;/p&gt;
&lt;h3 id=&quot;device-expansion&quot;&gt;&lt;a href=&quot;#device-expansion&quot; aria-label=&quot;device expansion permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Device Expansion&lt;/h3&gt;
&lt;p&gt;Hardware has gotten good, but is it that good? In short yes, but we&apos;ll need some help. Look at the Apple Thunderbolt Display.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cl.ly/2K212P1A070n3J2g3Y1O/Apple-Thunderbolt-Display1.jpg&quot; alt=&quot;Apple Thunderbolt Display&quot;&gt; Apple Thunderbolt Display&lt;/p&gt;
&lt;p&gt;The Thunderbolt port essentially extends the bus of the computer to add capabilities. This is fairly subtle in their current use of adding ethernet, soundcard, and an extra usb host - that could essentially be done with a USB hub and internally attached devices, but we could take it farther. Our phone just isn&apos;t going to have the graphics capabilities to drive a 27&quot; display at decent resolution. Our dock devices (the laptop clamshell, and the PC) could have their own graphics hardware, and even RAM to extend the capabilities of the device.&lt;/p&gt;
&lt;p&gt;The Asus Transformer is another a good example. It overcomes the obvious limitations of this kind of device: the battery. The tablet itself gets pretty decent battery life, but it gets even longer when you&apos;re plugged into the keyboard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cl.ly/0f3W3z1C0C233q0N1b1N/ASUS-Transformer-Prime-2.jpg&quot; alt=&quot;Asus Transformer Prime&quot;&gt; Asus Transformer Prime&lt;/p&gt;
&lt;p&gt;In my previous examples, our phone in the laptop clamshell could have extra battery, the desktop dock is probably plugged in and could charge as well, and other docks around the house.&lt;/p&gt;
&lt;h3 id=&quot;what-else-needs-to-happen&quot;&gt;&lt;a href=&quot;#what-else-needs-to-happen&quot; aria-label=&quot;what else needs to happen permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What else needs to happen?&lt;/h3&gt;
&lt;p&gt;Not much, and I think it&apos;s going to happen soon. Software and marketing are the biggest barriers. Someone will have to have an open-enough technology stack for users to feel comfortable with just one device. The software will need to be able to operate in a wide variety of modes with a wide variety of inputs. Users are going to have be given a device that they can feel is an extension of themselves - they&apos;re really going to invest a lot of themselves into this one device, so it&apos;ll have to be rock solid and capable with no compromises. All of these things are doable.&lt;/p&gt;
&lt;p&gt;We&apos;re very, very close.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[We're hiring a lead interface designer+developer]]></title><description><![CDATA[Here's a little about &yet.Our team loves to do great things and get stuff done. We know that doing good work is how you get to do more of…]]></description><link>https://blog.andyet.com/2012/07/07/were-hiring-a-lead-interface-designerdeveloper/</link><guid isPermaLink="false">https://blog.andyet.com/2012/07/07/were-hiring-a-lead-interface-designerdeveloper/</guid><pubDate>Sat, 07 Jul 2012 20:49:35 GMT</pubDate><content:encoded>&lt;h3 id=&quot;heres-a-little-about-yet&quot;&gt;&lt;a href=&quot;#heres-a-little-about-yet&quot; aria-label=&quot;heres a little about yet permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here&apos;s a little about &amp;#x26;yet.&lt;/h3&gt;
&lt;p&gt;Our team loves to do great things and get stuff done. We know that doing good work is how you get to do more of what you&apos;re passionate about, so we always aim to go above and beyond.&lt;/p&gt;
&lt;p&gt;We build products like &lt;a href=&quot;http://andbang.com&quot;&gt;And Bang&lt;/a&gt;, our team collaboration app—and, in doing so, create new tools and techniques that help others do new and innovative work in their products. Disqus, for example, uses &lt;a href=&quot;http://thoonk.com&quot;&gt;Thoonk&lt;/a&gt; as a critical piece of its realtime commenting architecture.&lt;/p&gt;
&lt;p&gt;We build things and provide consulting for clients, including companies whose names we can&apos;t mention but who nonetheless you know well and whose products you&apos;re almost certainly attached to all day long.&lt;/p&gt;
&lt;p&gt;We put on conferences, including &lt;a href=&quot;http://krtconf.com&quot;&gt;the Keeping it Realtime Conference&lt;/a&gt; (now in its second year).&lt;/p&gt;
&lt;p&gt;We invest massively in our local community. We founded our area&apos;s first design/developer community (doctype society) and helped its first coworking space get going. (Really awesome people run it who are not us, we&apos;re just lead cheerleaders.)&lt;/p&gt;
&lt;p&gt;&amp;#x26;yet is completely bootstrapped, self-funded, and has no plans of selling out to anyone. We&apos;ve grown from one to 18 in four and a half years. Nearly every new member of our team was individually and specifically invited—we had these people in our sights as the best at what they do and wanted to add them and &lt;em&gt;only&lt;/em&gt; them—some we even waited up to three years to add. This job posting is a rare, rare, time where we&apos;re actually opening up a position.&lt;/p&gt;
&lt;p&gt;What&apos;s it like to work at &amp;#x26;yet? All of our team calls this the best job they&apos;ve ever had.&lt;/p&gt;
&lt;p&gt;Here&apos;s what our newest hire said three weeks in: &lt;/p&gt;
&lt;p&gt;&quot;Do you all still realize how awesome this team is? Maybe you&apos;ve forgotten cause you&apos;re getting used to it and incorrectly think every other company has this kind of team. They don&apos;t.&quot;&lt;/p&gt;
&lt;p&gt;And &lt;a href=&quot;http://andyet.net/blog/2012/may/30/dr-strangeco-or-how-i-learned-to-stop-worrying-and/&quot;&gt;here&apos;s what another wrote&lt;/a&gt; a year and a half in.&lt;/p&gt;
&lt;p&gt;Our four longest tenured team members are still thrilled every week we still get to do this awesome &amp;#x26;yet thing together—and blown away by how far it&apos;s run in its first four years. &lt;/p&gt;
&lt;p&gt;Even still, we feel like we&apos;re just getting started and that this next year is going to be the most significant one we&apos;ve ever had—by miles.&lt;/p&gt;
&lt;p&gt;So enough about us. Let&apos;s talk about you.&lt;/p&gt;
&lt;h3 id=&quot;youyou-my-friendwould-play-a-huge-role-on-our-team-right-out-of-the-gates-if-you-had-these-qualifications&quot;&gt;&lt;a href=&quot;#youyou-my-friendwould-play-a-huge-role-on-our-team-right-out-of-the-gates-if-you-had-these-qualifications&quot; aria-label=&quot;youyou my friendwould play a huge role on our team right out of the gates if you had these qualifications permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;You—&lt;em&gt;you, my friend&lt;/em&gt;—would play a huge role on our team right out of the gates if you had these qualifications:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You&apos;re a leader—first of yourself. You help drive projects in quality and completeness. You can&apos;t stand being blocked from getting things done and you know how to get unblocked. You strongly prefer not to be managed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&apos;re willing to ask questions, look dumb, be wrong, take risks, and fail. You like the idea of committing to a project that means you&apos;ll need to learn a number of new skills along the way and do things you&apos;ve never done before.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You take way more of your share of blame and give way more than your share of credit.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&apos;re not an Awesome Rock Star Ninja Superstar. When you think about it, you&apos;re happy with how much better you are today than you were yesterday. You&apos;re good but painfully humble about it because you know how much you have to grow and how much you can learn from those around you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&apos;re a good communicator and play well with others, recognizing conflict is a creative force when handled correctly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&apos;re opinionated and you know how to state your position without being offensive and argue your point without being defensive. (And, when you do get defensive, you know how to own up to it and revisit the conversation with a fresh attitude.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You accept criticism of your work and take it well. It may hurt because you care about your work and put your heart into it, but you value the result of being able to make several great iterations based on feedback. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&apos;re a great student and teacher. You don&apos;t ever want to &quot;arrive&quot;--you just want to keep growing. You use Twitter to connect with and learn from people at the top of our industry.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You love finding ways to make things better—your work, others&apos; work, and your collaboration together.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reading this list makes your heart pound at least a little bit.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;oh-skills-right-those-are-important-too&quot;&gt;&lt;a href=&quot;#oh-skills-right-those-are-important-too&quot; aria-label=&quot;oh skills right those are important too permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Oh, skills? Right. Those are important, too.&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Your designs look great and people you respect tell you so.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You love building interfaces. So much. And what you love to build is simple and clear design that works well and is visually minimalistic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You love designing in the browser with CSS. You&apos;re constantly reading and discovering the latest methods and sharing them. You know how to build with responsive design methods. You use and love a preprocessor (like Sass, Less, or Stylus).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Your HTML is carefully considered because (1) doing so informs the logical structure of the site and (2) good markup is great supporting documentation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&apos;re very at home with front-end Javascript, comfortable with clientside MVC (a la Backbone or Ember), and you&apos;ve built something with Node.js.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You know the basics of Git and you&apos;ve worked in a web framwork of some sort—Rails, Node.js, or Django.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&apos;re a strong copywriter and understand basic marketing. Your witty, engaging, and clear writing knows its audience, cuts to the point, and demonstrates you know how to sell without sounding like a salesman.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;heres-what-you-get-for-being-part-of-our-team&quot;&gt;&lt;a href=&quot;#heres-what-you-get-for-being-part-of-our-team&quot; aria-label=&quot;heres what you get for being part of our team permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here&apos;s what you get for being part of our team.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Competitive salary&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Awesome benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Flexible hours&lt;/li&gt;
&lt;li&gt;401(k)&lt;/li&gt;
&lt;li&gt;Vacation / sick leave / sick kid leave&lt;/li&gt;
&lt;li&gt;Health insurance&lt;/li&gt;
&lt;li&gt;High-end hardware&lt;/li&gt;
&lt;li&gt;Cell phone + data plan&lt;/li&gt;
&lt;li&gt;All-you-can-read Kindle account&lt;/li&gt;
&lt;li&gt;Travel opportunities&lt;/li&gt;
&lt;li&gt;Bonuses&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;heres-what-you-should-do-next&quot;&gt;&lt;a href=&quot;#heres-what-you-should-do-next&quot; aria-label=&quot;heres what you should do next permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Here&apos;s what you should do next.&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Write us something to introduce yourself.&lt;/li&gt;
&lt;li&gt;Go item by item through the two lists above and responding to them—honestly—about yourself. Give yourself a 1-10 rating and add your comments for each.&lt;/li&gt;
&lt;li&gt;Send us examples of your work and links to where you&apos;re at online (twitter, github, personal site).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Send everything to &lt;a href=&quot;mailto:apply@andyet.net&quot;&gt;apply@andyet.net&lt;/a&gt;. Show us you&apos;re a great fit by going above and beyond the requirements for what&apos;s listed above.&lt;/p&gt;
&lt;p&gt;We&apos;re looking forward to hearing from you!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Web clients as "just another client"]]></title><description><![CDATA[The other day, DHH1 tweeted this:Forcing your web ui to be "just another client" of your API violates the first rule of distributed systems…]]></description><link>https://blog.andyet.com/2012/06/15/web-clients-as-just-another-client/</link><guid isPermaLink="false">https://blog.andyet.com/2012/06/15/web-clients-as-just-another-client/</guid><pubDate>Fri, 15 Jun 2012 12:09:00 GMT</pubDate><content:encoded>&lt;p&gt;The other day, DHH[1] tweeted this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Forcing your web ui to be &quot;just another client&quot; of your API violates the first rule of distributed systems: Don&apos;t write distributed systems.&lt;/p&gt;
&lt;p&gt;-- DHH (@dhh) &lt;a href=&quot;https://twitter.com/dhh/status/212663775101333505&quot;&gt;June 12, 2012&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In building the new Basecamp, 37signals chose to do much of the rendering on the server-side and have been rather vocal about that, bucking the recent trend to build really richly interrative, client-heavy apps. They cite speed, simplicity and cleanliness. I quote DHH, again:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It&apos;s a perversion to think that responding to Ajax with HTML fragments instead of JSON is somehow dirty. It&apos;s simple, clean, and fast.&lt;/p&gt;
&lt;p&gt;-- DHH (@dhh) &lt;a href=&quot;https://twitter.com/dhh/status/212658401702973442&quot;&gt;June 12, 2012&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Personally, I think this generalization is a bit short-sighted. &lt;/p&gt;
&lt;p&gt;The &quot;rule&quot; that is cited in the first tweet about distributed sytstems is from Martin Fowler who says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;First Law of Distributed Object Design: Don&apos;t distribute your objects!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, yes, duplicating state into the client is essentially just that: you&apos;re distributing your objects. I&apos;m not saying I&apos;m wiser than Mr. Fowler, but I do know that keeping client state can make an app much more useful and friendly. &lt;/p&gt;
&lt;p&gt;Take Path for iPhone. It caches state, so if you&apos;re offline you can read posts from your friends. You can also post new updates while offline that just seemlessly get posted when you&apos;re back on a network. That kind of use case is simply impossible unless you&apos;re willing to duplicate state to the client. &lt;/p&gt;
&lt;p&gt;As application developers we&apos;re not trying to dogmatically enforce &quot;best practices&quot; of computer science just for the sake of dogma, we&apos;re trying to build great experiences. So as soon as we want to support that type of use case, we have to agree that it&apos;s OK to do it in some circumstances. &lt;/p&gt;
&lt;p&gt;As some have pointed out and DHH acknowledged later, even Basecamp goes against his point with the calendar. In order to add the type of user experience they want, they do clientside MVC. They store some state in the client and do some client-side rendering. So, what&apos;s the difference in that case?&lt;/p&gt;
&lt;p&gt;I&apos;m not saying &lt;em&gt;all&lt;/em&gt; server side rendering is bad. I&apos;m just saying, why not pick one or the other? It seems to me (and I actually speak from experience here) that things get really messy once you start mixing presentation and domain logic.&lt;/p&gt;
&lt;p&gt;As it turns out, Martin Fowler actually wrote &lt;a href=&quot;http://martinfowler.com/ieeeSoftware/separation.pdf&quot;&gt;A WHOLE PAPER about separating presentation from domain logic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The other point I&apos;d like to make is this: What successful, interesting web application do you know/use/love that doesn&apos;t have multiple clients? &lt;/p&gt;
&lt;p&gt;As soon as you have any non-web client, such as an iPhone app, or a dashboard widget or a CLI or some other webapp that another developer built, you now need a seperate data API anyway.&lt;/p&gt;
&lt;p&gt;Obviously, 37signals has an API. But, gauging by &lt;a href=&quot;https://github.com/37signals/bcx-api/#api-still-under-development&quot;&gt;the docs&lt;/a&gt;, there are pieces of the API that are incomplete. Another benefit of dog-fooding your own API is that you can&apos;t ship with an incomplete API if you built your whole app on it.&lt;/p&gt;
&lt;p&gt;We&apos;re heads-down on the next version of &lt;a href=&quot;http://andbang.com&quot;&gt;And Bang&lt;/a&gt; which is built &lt;em&gt;entirely&lt;/em&gt; on what will be our public API. This re-engineering has been no small undertaking, but we feel it will be well worth the effort.&lt;/p&gt;
&lt;p&gt;The most interesting apps we use are not merely experienced through a browser anymore. APIs are the one true cross-platform future you can safely bank on.&lt;/p&gt;
&lt;p&gt;I&apos;m all ears if you have a differing opinion. Hit me up on twitter &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; and follow &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/andbang&quot;&gt;@andbang&lt;/a&gt; if you&apos;re curious about what else we&apos;re up to. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;[1] DHH (David Heinemeier Hansson) of Ruby on Rails and 37signals fame is not scared to state his opinions. I think everyone would agree that his accomplishments give him the right to do so. To be clear, I have nothing but respect for 37 Signals. Frankly, their example is a huge source of inspiration for bootstrapped companies like ours at &amp;#x26;yet.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Dr. StrangeCo or how I learned to stop worrying and love my job]]></title><description><![CDATA[This morning I had an epiphany of sorts.I received yet another recruitment message from a high profile tech company. I'm sure many of you…]]></description><link>https://blog.andyet.com/2012/05/30/dr-strangeco-or-how-i-learned-to-stop-worrying-and/</link><guid isPermaLink="false">https://blog.andyet.com/2012/05/30/dr-strangeco-or-how-i-learned-to-stop-worrying-and/</guid><pubDate>Wed, 30 May 2012 10:47:31 GMT</pubDate><content:encoded>&lt;p&gt;This morning I had an epiphany of sorts.&lt;/p&gt;
&lt;p&gt;I received yet another recruitment message from a high profile tech company. I&apos;m sure many of you receive lots of them, too. But this time, as I was reading the email, I realized that I can&apos;t think of a job offer that would convince me to walk away from my current employer.&lt;/p&gt;
&lt;p&gt;Why? I work at a weird company. A company where most of us are pretty happy with our work, our co-workers and our employer most of the time. You see, at &amp;#x26;yet, we have discovered that the keys to employee happiness are simple. They are not a set of HR tricks or esoteric geek benefits. Employees are humans, and the keys to our happiness are the keys to human happiness.&lt;/p&gt;
&lt;p&gt;I believe that everyone is on this little planet for a reason and is &apos;wired&apos; to be truly amazing at a handful of things (at least a handful, maybe more). Because of this feature of our existence, we are most likely to be happy if we are able both to discover and to do those things. The chances skyrocket if we can also do them with excellence, companionship, and appreciation.&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet are makers; we are creators. We build things because it is who we are. What do we make? We make applications for humans and APIs for machines, artful photographs and insightful videos, helpful blog posts and cutting-edge conferences, the ultimate toasted bagel and killer pozole, proven security processes and experimental work spaces.&lt;/p&gt;
&lt;p&gt;We are happy because our employer is committed to our well-being as much as to making a buck. We are happy because we know and celebrate each other&apos;s successes. [1] We are happy because our processes and environment are tailored more to support excellent creating and less to profit optimization and legal ass-covering. We are happy because being who we are and becoming who we can be is supported, not subverted, by the business team.&lt;/p&gt;
&lt;p&gt;I believe that at &amp;#x26;yet we are at our core a development shop, and that is the key to our high levels of happiness, creativity and output. We are not a software development shop as our tagline would indicate: &quot;We make web &amp;#x26; mobile stuff for human people.&quot; That tagline is for your benefit, dear reader; it is why you might wish to engage us to work for you. We ARE a development shop, but what we ultimately aim to develop is people: as humans (being) first and as skilled artisans, artists, engineers, facilitators and communicators (doing) second.&lt;/p&gt;
&lt;p&gt;Ultimately, this priority serves both our team and our clients best because, as we develop our ultimate product--a team of happy, talented humans, we are passionate about our individual and group creations because they are an extension of our core purpose.&lt;/p&gt;
&lt;p&gt;We make things with the intent that they should increase the happiness and humanity in the daily life of our clients and those they serve.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;1. We created &lt;a href=&quot;http://andbang.com&quot;&gt;And Bang&lt;/a&gt; and use &lt;a href=&quot;http://gingerhq.com&quot;&gt;Ginger&lt;/a&gt; largely for this purpose.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Maximum viable products]]></title><description><![CDATA[Panic is on &yet's short list of Hero Companies.We had the privilege of interviewing founders Cabel Sasser and Steven Frank shortly before…]]></description><link>https://blog.andyet.com/2012/05/25/maximum-viable-products/</link><guid isPermaLink="false">https://blog.andyet.com/2012/05/25/maximum-viable-products/</guid><pubDate>Fri, 25 May 2012 12:14:49 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://panic.com&quot;&gt;Panic&lt;/a&gt; is on &amp;#x26;yet&apos;s short list of Hero Companies.&lt;/p&gt;
&lt;p&gt;We had the privilege of interviewing founders &lt;a href=&quot;http://twitter.com/Cabel&quot;&gt;Cabel Sasser&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/stevenf&quot;&gt;Steven Frank&lt;/a&gt; shortly before Panic shipped their highly anticipated web development app, Coda 2.&lt;/p&gt;
&lt;p&gt;Here&apos;s one segment in which Cabel is asked about building &quot;minimum viable products&quot;.&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/42851640&quot; height=&quot;281&quot; width=&quot;500&quot; allowfullscreen webkitallowfullscreen mozallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Mel is editing a short film from the interviews that will be released—when? When she&apos;s finished. :) &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;Follow @andyet on Twitter&lt;/a&gt; and we&apos;ll let you know when it&apos;s ready.&lt;/p&gt;
&lt;p&gt;We all love doing quality work. Emboldened by Cabel&apos;s answer, we&apos;ll make no excuses for taking time. And, like Panic, there are no investors pounding on us.&lt;/p&gt;
&lt;p&gt;On that note, we aimed to release a new major version of our team same-page-ification app, &lt;a href=&quot;http://andbang.com&quot;&gt;And Bang&lt;/a&gt;, within the first half of this year, but we&apos;ve made so many discoveries in the past six months, we&apos;re committed to seeing through a significant revision rather than a mere iteration.&lt;/p&gt;
&lt;p&gt;Our team feels that And Bang 1.0 s a useful tool we&apos;re proud of. We feel like the next version of And Bang is something special, from technology to philosophy.&lt;/p&gt;
&lt;p&gt;We have many customers who&apos;ve been eagerly awaiting our second release. Thank you so much for your patience and terrific feedback. We think you&apos;ll love the next version of And Bang.&lt;/p&gt;
&lt;p&gt;To stay in the loop, &lt;a href=&quot;http://twitter.com/andbang&quot;&gt;follow @andbang on Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;----&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is this?&lt;/strong&gt; We&apos;re eager to show the human side of the technologies we love, so we&apos;re creating short films about people who inspire us. We &lt;a href=&quot;http://andyet.net/blog/2011/nov/2/an-interview-with-amber-case-cyborg-anthropologist/&quot;&gt;interviewed Geoloqi&apos;s Amber Case&lt;/a&gt; a few months ago, as the first in this series&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Compromising the integrity of the npm registry.]]></title><description><![CDATA[Recently it was disclosed that the NPM registry leaked the usernames, salts and sha1 hashes of registry users. Essentially this amounts to a…]]></description><link>https://blog.andyet.com/2012/03/08/compromising-the-integrity-of-the-npm-registry/</link><guid isPermaLink="false">https://blog.andyet.com/2012/03/08/compromising-the-integrity-of-the-npm-registry/</guid><pubDate>Thu, 08 Mar 2012 11:20:52 GMT</pubDate><content:encoded>&lt;p&gt;Recently it was &lt;a href=&quot;https://gist.github.com/2001456&quot;&gt;disclosed&lt;/a&gt; that the NPM registry leaked the usernames, salts and sha1 hashes of registry users. Essentially this amounts to a breach of about 4k user accounts.&lt;/p&gt;
&lt;p&gt;The issue has since been taken care of and users are being asked (not forced) to change their passwords. The leaked data has been available for a very long time, probably since the registry has been using couch. Everyone should be resetting their passwords. Now.&lt;/p&gt;
&lt;p&gt;I first found out and notified &lt;a href=&quot;https://twitter.com/#!/izs&quot;&gt;Isaac&lt;/a&gt; about this on 3/1/2012. I only found out about this because I was looking for potential ways that &lt;a href=&quot;https://andbang.com&quot;&gt;&amp;#x26;!&lt;/a&gt; could be compromised.&lt;/p&gt;
&lt;p&gt;One of the ways we build our development and production environments is by using npm to install packages. I was curious just how hard it would be to compromise the integrity of packages published to the registry, turns out not very. It’s great to point out however that npm is meant to be a distribution channel. It’s a free and open service in which anybody can distribute packages. It’s not meant to provide any level of integrity and quality checking. As developers we are responsible for the code that executes in our environments. Maybe checking verified packages into your projects repository isn’t such a bad idea after all.&lt;/p&gt;
&lt;p&gt;It took only 24 hours using an old spare machine to crack 25% of the passwords. Very little effort or CPU power.&lt;/p&gt;
&lt;p&gt;Passwords cracked included prominent, well respected members of the node.js community that control publishing rights to widely used packages.&lt;/p&gt;
&lt;p&gt;To be clear, this was not done for the sake of gaining access to those passwords and the data has been destroyed and I never tried to log in with any account. It was just a test of how hard it would be to abuse it and thus, what level of actual threat it represented.&lt;/p&gt;
&lt;p&gt;There are some great comments on if this was a couch problem or a npm problem in this &lt;a href=&quot;http://news.ycombinator.com/item?id=3679996&quot;&gt;thread&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;During that time I also discovered a number of persistent and reflected cross-site scripting vulnerabilities that were patched in this &lt;a href=&quot;https://github.com/isaacs/npmjs.org/pull/56&quot;&gt;pull request&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally I would like to thank Isaac for taking the time to communicate with me over email about this, keep me updated as things progressed, and most importantly shipping a fix and being transparent with the node community.&lt;/p&gt;
&lt;p&gt;I&apos;m very interested in comments on this and appreciate feedback either via email (&lt;a href=&quot;mailto:baldwin@andyet.net&quot;&gt;baldwin@andyet.net&lt;/a&gt;) or twitter &lt;a href=&quot;https://twitter.com/#!/adam_baldwin&quot;&gt;@adam_baldwin&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;tldr&quot;&gt;&lt;a href=&quot;#tldr&quot; aria-label=&quot;tldr permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;tl;dr&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Only 24 hours to crack 25% of the user passwords.&lt;/li&gt;
&lt;li&gt;It’s not required for you to reset your password, do so anyway.&lt;/li&gt;
&lt;li&gt;You are responsible for the code you run in production, not NPM.&lt;/li&gt;
&lt;li&gt;Serious thank you to &lt;a href=&quot;https://twitter.com/#!/izs&quot;&gt;@izs&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/#!/_jhs&quot;&gt;@_jhs&lt;/a&gt; for shipping a fix &amp;#x26; being transparent&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Devops and security vodcast: code quality & helpful tools]]></title><description><![CDATA[&yet's ops and security guys hash it out in this latest vodcast.Nathan Lafreniere talks about what's in his devops toolkit, his code…]]></description><link>https://blog.andyet.com/2012/02/17/devops-and-security-vodcast-code-quality-helpful-t/</link><guid isPermaLink="false">https://blog.andyet.com/2012/02/17/devops-and-security-vodcast-code-quality-helpful-t/</guid><pubDate>Fri, 17 Feb 2012 14:02:29 GMT</pubDate><content:encoded>&lt;p&gt;&amp;#x26;yet&apos;s ops and security guys hash it out in this latest vodcast.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://twitter.com/quitlahok&quot;&gt;Nathan Lafreniere&lt;/a&gt; talks about what&apos;s in his devops toolkit, his code deployment process, how ops can help maintain code quality, and his new documentation library, &lt;a href=&quot;https://github.com/andyet/ape&quot;&gt;ape&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://twitter.com/adam_baldwin&quot;&gt;Adam Baldwin&lt;/a&gt; discusses his new Node.js header security library for express, &lt;a href=&quot;https://github.com/andyet/helmet&quot;&gt;helmet&lt;/a&gt;, a few headers that most apps should be including by default now, and some random bits about realtime security.&lt;/p&gt;
&lt;p&gt;Fortunately for you this particular cut doesn&apos;t include Adam singing &lt;a href=&quot;http://www.youtube.com/watch?v=YjaZNYSt7o0&quot;&gt;Russian Unicorn&lt;/a&gt; but it does feature a yeti and Adam doing what he would consider dancing.&lt;/p&gt;
&lt;p&gt;Please let us know what you would like to hear about in the future regarding ops and security.&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/36861009?title=0&amp;byline=0&amp;portrait=0&quot; height=&quot;287&quot; width=&quot;510&quot; allowfullscreen webkitallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Credits:&lt;/p&gt;
&lt;p&gt;&quot;Talent&quot;: &lt;a href=&quot;http://twitter.com/quitlahok&quot;&gt;Nathan&lt;/a&gt; (left) and &lt;a href=&quot;http://twitter.com/adam_baldwin&quot;&gt;@adam_baldwin&lt;/a&gt; (right).&lt;/p&gt;
&lt;p&gt;Video filmed and produced by the awesome Ms. &lt;a href=&quot;/team/melanie/&quot;&gt;Mel&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Redis reliability for realtime apps]]></title><description><![CDATA[The ProblemWhen I was at FOSDEM last weekend, I talked to several people who couldn't believe that I would use Redis as a primary database…]]></description><link>https://blog.andyet.com/2012/02/09/redis-reliability-for-realtime-apps/</link><guid isPermaLink="false">https://blog.andyet.com/2012/02/09/redis-reliability-for-realtime-apps/</guid><pubDate>Thu, 09 Feb 2012 12:02:35 GMT</pubDate><content:encoded>&lt;h3 id=&quot;the-problem&quot;&gt;&lt;a href=&quot;#the-problem&quot; aria-label=&quot;the problem permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Problem&lt;/h3&gt;
&lt;p&gt;When I was at FOSDEM last weekend, I talked to several people who couldn&apos;t believe that I would use &lt;a href=&quot;http://redis.io&quot;&gt;Redis&lt;/a&gt; as a primary database in single page webapps. When mentioning that on Twitter, someone said, &quot;Redis really only works if it&apos;s acceptable to lose data after a crash.&quot;&lt;/p&gt;
&lt;p&gt;For starters, read &lt;a href=&quot;http://redis.io/topics/persistence&quot;&gt; http://redis.io/topics/persistence&lt;/a&gt;. What makes Redis different from other databases in terms of reliability is that a command can return &quot;OK&quot; before the data is written to disk (I&apos;ll get to this). Beyond that, it is easy to take snapshots, compress append-only log files, configure fsync behavior in Redis. There are tests for dealing with disk access suddenly cut off while writing, and steps are taken to prevent this from causing corruption. In addition, you have &lt;code class=&quot;language-text&quot;&gt;redis-check-aof&lt;/code&gt; for dealing with log file corruption. &lt;/p&gt;
&lt;p&gt;Note that because you have fine tuned control over how fsync works, you don&apos;t have to rely on the operating system to make sure that operations are written to disk. &lt;/p&gt;
&lt;h3 id=&quot;no-really-what-was-the-problem-again&quot;&gt;&lt;a href=&quot;#no-really-what-was-the-problem-again&quot; aria-label=&quot;no really what was the problem again permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;No Really, What Was the Problem Again?&lt;/h3&gt;
&lt;p&gt;Since commands fail in any database, client libraries wait for OKs, Errors, and Timeouts to deal with data reliability. Every database based application has to deal with the potential error. The difference is that we expect the pattern to be command-result based, when in fact, we can take a more asynchronous approach with Redis. &lt;/p&gt;
&lt;h3 id=&quot;asynchronous-reliability&quot;&gt;&lt;a href=&quot;#asynchronous-reliability&quot; aria-label=&quot;asynchronous reliability permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Asynchronous reliability&lt;/h3&gt;
&lt;p&gt;The real difference is that Redis will return an OK as long as it was written to RAM (see Antirez&apos;s clarification in the comments) while other databases tend to send OK only after the data is written to disk. We can still get on par (and beyond) with other database reliability easily enough by having a very simple check that you may be doing anyway without realizing it. When sending any command or atomic group of commands to Redis in the context of a single page app, I always send some sort of &lt;code class=&quot;language-text&quot;&gt;PUBLISH&lt;/code&gt; at the end. This publish bubbles back up to update the user clients as well as inform any other interested party (separate cluster processes for example) about what is going on in the database application. If the client application lets the user know that it didn&apos;t get an update corresponding with a user action within a certain amount of time, then we know the command didn&apos;t complete. Beyond this, we can write to a Redis &lt;em&gt;master&lt;/em&gt; and &lt;code class=&quot;language-text&quot;&gt;LISTEN&lt;/code&gt; for publishes on a Redis &lt;em&gt;slave&lt;/em&gt;! Now the client application can know that the data has been saved on more than one server; that sounds pretty reliable to me. &lt;/p&gt;
&lt;p&gt;Using this information, the client application can intelligently deal with user action reliability all the way to the slave, and inform users with a simple error, resubmit their action without prompting, or request that the server do some sort of reliability check (in or out of context of the user action), etc. &lt;/p&gt;
&lt;h3 id=&quot;tldr&quot;&gt;&lt;a href=&quot;#tldr&quot; aria-label=&quot;tldr permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;tl;dr&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Single page app sends a command &lt;/li&gt;
&lt;li&gt;Application server runs an atomic action on Redis &lt;em&gt;master&lt;/em&gt;. &lt;/li&gt;
&lt;li&gt;Redis master syncs to Redis &lt;em&gt;slave&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;PUBLISH&lt;/code&gt; at the end of said atomic action routes to application server from Redis &lt;em&gt;slave&lt;/em&gt;. &lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;PUBLISH&lt;/code&gt; routes to single page app that sent the command, and thus the client application knows that said atomic action succeeded on two servers. &lt;/li&gt;
&lt;li&gt;If the client application hasn&apos;t heard a published confirmation, the client can deal with this as an error however it deems appropriate.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;further-thoughts&quot;&gt;&lt;a href=&quot;#further-thoughts&quot; aria-label=&quot;further thoughts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Further Thoughts&lt;/h3&gt;
&lt;p&gt;Data retention, reliability, scaling, and high availability are all related concepts, but not the same thing. This post specifically deals with data retention. There are existing strategies and efforts for the other related problems that aren&apos;t covered in this post. &lt;/p&gt;
&lt;p&gt;If data retention is your primary need from a database, I recommend giving Riak a look. I believe in picking your database based on your primary needs. With Riak, commands can wait for X number of servers in the cluster to agree on a result, and while we can do something similar on the application level with Redis, Riak comes with this baked in. &lt;/p&gt;
&lt;p&gt;David Search commented while reviewing this post, &quot;Most people don&apos;t realize that a fsync doesn&apos;t actually guarantee data is written these days either (depending on the disk type/hardware raid setup/etc).&quot; This further strengthens the concept of confirming that data exists on multiple servers, either asynchronously as this blog post outlines, or synchronously like with Riak. &lt;/p&gt;
&lt;h3 id=&quot;about-nathan-fritz&quot;&gt;&lt;a href=&quot;#about-nathan-fritz&quot; aria-label=&quot;about nathan fritz permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;About Nathan Fritz&lt;/h3&gt;
&lt;p&gt;Nathan Fritz aka &lt;a href=&quot;https://twitter.com/#!/fritzy&quot;&gt;@fritzy&lt;/a&gt; works at &amp;#x26;yet as the Chief Architect. He is currently working on a book called &quot;Redis Theory and Patterns.&quot;&lt;/p&gt;
&lt;p&gt;If you’re building a single page app, keep in mind that &amp;#x26;yet offers consulting, training and development services. Send Fritzy an email (&lt;a href=&quot;mailto:nathan@andyet.net&quot;&gt;nathan@andyet.net&lt;/a&gt;) and tell us what we can do to help.&lt;/p&gt;
&lt;h3 id=&quot;update-comment-from-antirez&quot;&gt;&lt;a href=&quot;#update-comment-from-antirez&quot; aria-label=&quot;update comment from antirez permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Update: Comment From Antirez&lt;/h3&gt;
&lt;p&gt;Antirez chimed in the comments to correct this post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;actually, it is much better than that ;)&lt;/p&gt;
&lt;p&gt;Redis with AOF enabled returns OK only &lt;em&gt;after&lt;/em&gt; the data was written on disk. Specifically (sometimes just transmitted to the OS via write() syscall, sometimes after also fsync() was called, depending on the configuration).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It returns OK when aof fsync mode is set to &apos;no&apos;, after the wirte(2) syscall is performed. But in this mode no fsync() is called.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It returns OK when aof fsync mode is set to &apos;everysec&apos; (the default) after write(2) syscall is performed. With the exception of a really busy disk that has still a fsync operation pending after one seconds. In that case, it logs the incident on disk and forces the buffer to be flushed on disk blocking if at least another second passes and still the fsync is pending.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It returns OK both after write(2) and fsync(2) if the fsync mode is &apos;always&apos;, but in that setup it is extremely slow: only worth it for really special applications.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Redis persistence is not less reliable compared to other databases, it is actually more reliable in most of the cases because Redis writes in an append-only mode, so there are no crashed tables, no strange corruptions possible.&quot;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[Adam Baldwin and Nathan LaFreniere are yetis.]]></title><description><![CDATA[Because we are huge fans of human namespace collisions and amazing people, we're adding two new members to our team: Adam Baldwin and Nathan…]]></description><link>https://blog.andyet.com/2011/12/16/adam-baldwin-and-nathan-lafreniere-are-yetis/</link><guid isPermaLink="false">https://blog.andyet.com/2011/12/16/adam-baldwin-and-nathan-lafreniere-are-yetis/</guid><pubDate>Fri, 16 Dec 2011 08:58:54 GMT</pubDate><content:encoded>&lt;p&gt;Because we are huge fans of human namespace collisions and amazing people, we&apos;re adding two new members to our team: &lt;a href=&quot;http://twitter.com/adam_baldwin&quot;&gt;Adam Baldwin&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/quitlahok&quot;&gt;Nathan LaFreniere&lt;/a&gt;, both in transition from &lt;a href=&quot;http://ngenuity-is.com&quot;&gt;nGenuity&lt;/a&gt;, the security company Adam Baldwin co-founded and built into a well-respected consultancy that has advised the likes of GitHub, AirBNB, and LastPass on security.&lt;/p&gt;
&lt;p&gt;We have relied on Adam and Nathan&apos;s services through nGenuity to inform, improve, and check our development process, validating and invalidating our team&apos;s work and process, providing education and correction along the way. We are thrilled to be able to bring these resources to bear with greater influence, while providing Adam Baldwin with the authority to improve areas in need of such.&lt;/p&gt;
&lt;h3 id=&quot;adam-baldwin&quot;&gt;&lt;a href=&quot;#adam-baldwin&quot; aria-label=&quot;adam baldwin permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Adam Baldwin&lt;/h3&gt;
&lt;p&gt;Adam Baldwin has served as &amp;#x26;yet&apos;s most essential advisor since our first year, providing me with confidence in venturing more into development as an addition to my initial web design freelance business, playing &quot;panoptic debugger&quot; when I struggled with it, helping us establish good policy and process as we built our team, improving our system operations, and always, always, bludgeoning us about the head regarding security.&lt;/p&gt;
&lt;p&gt;It really can&apos;t be expressed how much respect I and our team at &amp;#x26;yet have for Adam and his work.&lt;/p&gt;
&lt;p&gt;He&apos;s uncovered &lt;a href=&quot;http://evilpacket.net/2009/jul/9/basecamp-one-wrong-click/&quot;&gt;Basecamp vulnerabilities&lt;/a&gt; that encouraged 37Signals to change their policies for &lt;a href=&quot;http://37signals.com/security-response&quot;&gt;handling reported vulnerabilities&lt;/a&gt;, found huge &lt;a href=&quot;http://evilpacket.net/2010/jan/14/mifi-geopwn/&quot;&gt;holes in Sprint/Verizon MiFi &lt;/a&gt;(that made for one of the most hilarious stories I&apos;ve been a part of), published vulnerabilities &lt;em&gt;twice&lt;/em&gt; to &lt;a href=&quot;http://evilpacket.net/2009/jul/9/rackspace-cloud-xss-root/&quot;&gt;root&lt;/a&gt; &lt;a href=&quot;http://evilpacket.net/2009/jul/9/theft-rackspace-cloud-api-key/&quot;&gt;Rackspace&lt;/a&gt;, shared research to uberhackers at DEFCON, and has provided security advice for a number of first-class web apps, including ones you&apos;re using today and conceivably right now.&lt;/p&gt;
&lt;p&gt;Adam Baldwin will be joining our team at &amp;#x26;yet as CSO—it&apos;s a double title: Chief of Software Operations and Chief Security Officer.&lt;/p&gt;
&lt;p&gt;Adam will be adding his security consultancy, alongside &amp;#x26;yet&apos;s other consulting services, but will also be overseeing our team&apos;s software processes, something he has informed, shaped, and helped externally verify since, I think, before most of our team was born.&lt;/p&gt;
&lt;p&gt;On a personal note (&lt;a href=&quot;http://adambrault.com/post/14303855561/an-announcement-not-involving-going-to-a-castle-but-in&quot;&gt;a longer version of which is here&lt;/a&gt;), I must say it&apos;s a real joy to be able to welcome one of my best friends into helping lead a business he helped build as much as anyone our team.&lt;/p&gt;
&lt;h3 id=&quot;nathan-lafreniere&quot;&gt;&lt;a href=&quot;#nathan-lafreniere&quot; aria-label=&quot;nathan lafreniere permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Nathan LaFreniere&lt;/h3&gt;
&lt;p&gt;As excited as I am personally to add Adam Baldwin, our dev team is even more thrilled about adding Nathan, whose services we have become well accustomed to relying on in our contract with nGenuity and in a large project where we&apos;ve served a mutual customer.&lt;/p&gt;
&lt;p&gt;Nathan is a multitalented dev/ops badass well-versed in automated deployment tools.&lt;/p&gt;
&lt;p&gt;He solves operations problems with a combination of experience, innovation, and willingness to learn new tools and approaches.&lt;/p&gt;
&lt;p&gt;He&apos;s already gained a significant depth of experience building custom production systems for Node.js, including some tools we&apos;ve come to rely on heavily for &amp;#x26;bang.&lt;/p&gt;
&lt;p&gt;Nathan&apos;s passion for well-architected, smoothly running, and meticulously monitored servers has helped our developers sleep at night, very literally.&lt;/p&gt;
&lt;p&gt;I know getting the luxury of having a huge amount of Nathan&apos;s time at our developers disposal sounds to them like diving into a pool of soft kittens who don&apos;t mind you diving on them and aren&apos;t hurt at all by it either oh and they&apos;re declawed and maybe wear dentures but took them out.&lt;/p&gt;
&lt;p&gt;So that&apos;s what we have for you today.&lt;/p&gt;
&lt;p&gt;We think you&apos;re gonna love it.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Realtime web app architecture with Thoonk: a series of tubes, not tables]]></title><description><![CDATA[Now you're thinking with feeds!When I look at a single-page webapp, all I see are feeds; I don't even see the UI anymore. I just see lists…]]></description><link>https://blog.andyet.com/2011/11/18/realtime-web-app-architecture-with-thoonk-a-series/</link><guid isPermaLink="false">https://blog.andyet.com/2011/11/18/realtime-web-app-architecture-with-thoonk-a-series/</guid><pubDate>Fri, 18 Nov 2011 08:58:35 GMT</pubDate><content:encoded>&lt;h3 id=&quot;now-youre-thinking-with-feeds&quot;&gt;&lt;a href=&quot;#now-youre-thinking-with-feeds&quot; aria-label=&quot;now youre thinking with feeds permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Now you&apos;re thinking with feeds!&lt;/h3&gt;
&lt;p&gt;When I look at a single-page webapp, all I see are feeds; I don&apos;t even see the UI anymore. I just see lists of items that I care about. Some of which only I have access to and some of which other groups have access to. I can change, delete, re-position, and add to the items on these feeds and they&apos;ll propagate to the people and entities that have access to them (even if it is just me on another device or at a later date).&lt;/p&gt;
&lt;p&gt;I&apos;ve seen it this way for years, but I haven&apos;t grokked it enough to articulate what I was seeing until now.&lt;/p&gt;
&lt;h3 id=&quot;what-thoonk-is&quot;&gt;&lt;a href=&quot;#what-thoonk-is&quot; aria-label=&quot;what thoonk is permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Thoonk Is&lt;/h3&gt;
&lt;p&gt;Thoonk is a series of higher-level objects built on &lt;a href=&quot;http://redis.io&quot;&gt;Redis&lt;/a&gt; that sends publish, edit, delete, and position events when they are changed. These objects are feeds for making real-time applications and feed services.&lt;/p&gt;
&lt;h3 id=&quot;what-is-a-thoonk-feed&quot;&gt;&lt;a href=&quot;#what-is-a-thoonk-feed&quot; aria-label=&quot;what is a thoonk feed permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is a Thoonk feed?&lt;/h3&gt;
&lt;p&gt;A Thoonk feed is a list of indexed data objects that are limited by topic and by what a single entity might subscribe to. An RSS/ATOM feed qualifies. What makes a Thoonk feed different from a table? A table is limited to a topic, but lacks single entity interest limitations. A Thoonk feed isn&apos;t just a message broker, it&apos;s a database-store that sends out events when the data changes.&lt;/p&gt;
&lt;p&gt;Let&apos;s use &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;bang&lt;/a&gt; as an example. Each team-member has a list of tasks. In a relational database we might have a table that looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;team_member_tasks

id | team_id | member_id | description | complete bool | etc.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Whenever a user renders their list, I would query that list, limiting by a specific user and a specific team.&lt;/p&gt;
&lt;p&gt;If we converted this table, without changing it, into a Thoonk feed, then we would only be able to subscribe to ALL tasks and not just the tasks of a particular team or member. So, instead, a Thoonk feed might look like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;team:&amp;lt;team_id&amp;gt;:member:&amp;lt;member_id&amp;gt;:tasks

{description: &amp;quot;&amp;quot;, completed: false, etc, etc}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now when the user wants a rendered list of tags, I can do one index look-up rather than three, and I am able to subscribe to changes on the specific team member&apos;s tasks, or even to &lt;code class=&quot;language-text&quot;&gt;team:353:member:*:tasks&lt;/code&gt; to subscribe to all of that team&apos;s tasks.&lt;/p&gt;
&lt;p&gt;[Note: I suppose you could arrange a relational database this way, but it wouldn&apos;t really be able to take advantage of SQL, nor could you subscribe to the table to get changes.]&lt;/p&gt;
&lt;h3 id=&quot;its-feeds-all-the-way-up&quot;&gt;&lt;a href=&quot;#its-feeds-all-the-way-up&quot; aria-label=&quot;its feeds all the way up permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;It&apos;s Feeds All the Way Up&lt;/h3&gt;
&lt;p&gt;If I use Thoonk subscribe-able feeds as my data-storage engine, life gets so much easier. When a user logs in, I can subscribe contextualized callbacks just for them to the feeds of data that they have access to read from. This way, if their data changes for any reason, by any process, by any server, it can bubble all the way up to the user without having to run any queries. I can also subscribe separate processes that can automatically scrub, pre-index, cull, or any number of tasks to any Thoonk feed a particular process cares about. I can use processes in mixed languages to provide monitoring and additional API&apos;s to the feeds.&lt;/p&gt;
&lt;h3 id=&quot;but-what-about-writes&quot;&gt;&lt;a href=&quot;#but-what-about-writes&quot; aria-label=&quot;but what about writes permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But What About Writes?&lt;/h3&gt;
&lt;p&gt;Let&apos;s not think in terms of writes. Writes are just changes to feed items (publishing, editing, deleting, repositioning) that writes the data to ram/disk and informs any subscribers of the change. Let&apos;s instead think in terms of user-actions. A user-action (such as delegating a task to another user in &amp;#x26;bang) needs ACL and may affect multiple feeds in a single call. If we defer user-actions to jobs (a special kind of Thoonk feed), we can easily isolate, scale, share, and distribute the business-logic involved in dealing with a user-action.&lt;/p&gt;
&lt;h3 id=&quot;what-are-thoonk-jobs&quot;&gt;&lt;a href=&quot;#what-are-thoonk-jobs&quot; aria-label=&quot;what are thoonk jobs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Are Thoonk Jobs?&lt;/h3&gt;
&lt;p&gt;Thoonk Jobs are items that represent business-logic needing to be done reliably, a single time, by any available worker. Jobs are consumed as fast as a worker-pool can consume them. A job feed is a list of job items, each of which may exist in the state of available, in-flight, and stalled. Available jobs are taken and are placed in an in-flight set while they are being processed. When the job is done, the job is removed from the in-flight set, and its item is deleted. If the worker fails to complete the job (either because of an error, distaste, or a monitoring process deciding that the job has timed out), the job may be placed back to the available list or the stalled set.&lt;/p&gt;
&lt;h3 id=&quot;why-use-thoonk-jobs-for-user-actions&quot;&gt;&lt;a href=&quot;#why-use-thoonk-jobs-for-user-actions&quot; aria-label=&quot;why use thoonk jobs for user actions permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why use Thoonk Jobs for User-Actions?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;User-actions that fail for some reason can be retried (you can also limit the # of retries).&lt;/li&gt;
&lt;li&gt;The work can be distributed across processes and servers.&lt;/li&gt;
&lt;li&gt;User-actions can burst much faster than the workers can handle them.&lt;/li&gt;
&lt;li&gt;A user-action that ultimately fails can be stalled, where an admin is informed to investigate and potentially edit and/or retry when the issue that caused it has been resolved or to test said resolution.&lt;/li&gt;
&lt;li&gt;Any process in any language can contribute jobs (and get results from them) without having to re-implement the business logic or ACL.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-last-one-is-a-doozy&quot;&gt;&lt;a href=&quot;#the-last-one-is-a-doozy&quot; aria-label=&quot;the last one is a doozy permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Last One is a Doozy&lt;/h3&gt;
&lt;p&gt;Scaling, reliability, monitoring and all of that is nice, but being able to build your application out rather than up is, I believe, the greatest reason for this approach. &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;bang&lt;/a&gt; is written in node.js, but if I have a &lt;a href=&quot;https://github.com/andyet/fermata&quot;&gt;favorite library for implementing a REST interface&lt;/a&gt; or an &lt;a href=&quot;https://github.com/fritzy/sleekxmpp&quot;&gt;XMPP interface&lt;/a&gt; written in Python or Ruby (or any other language), I can quickly put that together and add it as a process. In fact, I can pretty much add any piece of functionality as a process without having to reload the rest of the application server, and really isolate a feature as its own process. User-actions from this process can be published to Thoonk Job feeds without having to worry about request validation or ACL since that is handled by the worker itself.&lt;/p&gt;
&lt;p&gt;Rather than having a very large, complex application, I can have a series of very small processes that automatically cluster and are informed of changes in areas of their specific concerns.&lt;/p&gt;
&lt;h3 id=&quot;scaling-beyond-redis&quot;&gt;&lt;a href=&quot;#scaling-beyond-redis&quot; aria-label=&quot;scaling beyond redis permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Scaling Beyond Redis&lt;/h3&gt;
&lt;p&gt;Our testing indicates that Redis will not be a choke point until we have nearly 100,000 active users. The plan to scale beyond that is to shard &amp;#x26;bang by teams. A quick look-up will tell us which server a team resides on, and users and processes can subscribe callbacks to connections on those servers. In that way, we can run many Redis servers, and theoretically scale vertically. High-availability is handled by a slave for each shard and a gossip protocol for promoting slaves.&lt;/p&gt;
&lt;h3 id=&quot;conflict-resolution-and-missed-updates&quot;&gt;&lt;a href=&quot;#conflict-resolution-and-missed-updates&quot; aria-label=&quot;conflict resolution and missed updates permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conflict Resolution and Missed Updates&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://andyet.net/blog/2011/nov/16/backbonejs-and-capsule-and-thoonk-oh-my-a-scalable/&quot;&gt;Henrik&apos;s recent post&lt;/a&gt; spawned a couple of questions about conflict resolution. First I&apos;ll give a deflection, and then I&apos;ll give a real answer.&lt;/p&gt;
&lt;p&gt;&amp;#x26;bang doesn&apos;t yet need conflict resolution. None of the writes are actually done on the client as they are all RPC calls which go into a job queue. Then the workers validate the payload, check the ACL, and update some feeds, at which point the data bubbles back up to the client. The feed updates are atomic, and happen quite quickly. Also, two users being able &quot;to edit the same item only comes up with delegated task, in which case the most recent edit wins.&lt;/p&gt;
&lt;p&gt;Ok, now the real answer. Thoonk is going to have revision history and incrementing revision numbers for 1.0. Each historical item is the same as the publish/edit/delete/reposition updates that are sent via pubsub. When a user change job is done, the client can send its current revision numbers for the feeds involved, and thus conflicts on an edit can be detected. The historical data should be enough data to facilitate some form of conflict resolution (determined by the application implementer). The revision numbers can also bubble up to the client, so the client can detect missing updates and ask for a replay from a given revision number.&lt;/p&gt;
&lt;p&gt;Currently we&apos;re punting on missed items. Anytime the &amp;#x26;bang user is disconnected, the app is disabled and refreshed when it is able to reconnect. A more elaborate solution using the new Thoonk features I just listed is probably coming and perhaps some real offline-mode support with local &quot;dirty&quot; changes that get resolved when you come back online.&lt;/p&gt;
&lt;h3 id=&quot;all-combined&quot;&gt;&lt;a href=&quot;#all-combined&quot; aria-label=&quot;all combined permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;All Combined&lt;/h3&gt;
&lt;p&gt;Using Thoonk, we were able to make &amp;#x26;bang scale to 10s of thousands of active users on a single server, burst user-activity beyond our choke-points, isolate user-action business-logic and ACL, automatically cluster to more servers and processes, choose any Redis client library supported language for individual features and interfaces, bubble data changes all the way up to the user regardless of the source of change, provide an easy way of iterating, and generally create a kick-ass, realtime, single-page webapp.&lt;/p&gt;
&lt;h3 id=&quot;can-i-use-thoonk-now&quot;&gt;&lt;a href=&quot;#can-i-use-thoonk-now&quot; aria-label=&quot;can i use thoonk now permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Can I Use Thoonk Now?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/andyet/thoonk.js&quot;&gt;Thoonk.js&lt;/a&gt; and &lt;a href=&quot;https://github.com/andyet/thoonk.py&quot;&gt;Thoonk.py&lt;/a&gt; are MIT licensed, and free to use. While we are using Thoonk.js in production and it is stable there, the API is not final. Currently I&apos;m moving the the feed logic to Redis Lua scripts, which will be officially supported in Redis 2.6 with an RC1 promised for this December. I plan to be ready for that. The Lua scripting will give us performance gains, and remove unnecessary extra logic to keep publish/edit/delete/reposition commands atomic, but most importantly it will allow us to share the core code with all implementations of Thoonk, allowing us to easily add and support more languages. As mentioned previously, as I do the Redis Lua scripting, I&apos;ll be adding revision history and revision numbers to feeds, which will facilitate conflict detection and replay of missed events.&lt;/p&gt;
&lt;p&gt;That said, feel free to comment, contribute, steal, or abuse the project in the meantime. A 1.0 release will indicate API stability, and I will encourage its use in production at that point. I will soon be breaking out the Lua scripts to their own git repo for easy implementation.&lt;/p&gt;
&lt;p&gt;If you want to keep an eye on what we&apos;re doing, follow me &lt;a href=&quot;http://twitter.com/frizty&quot;&gt;@fritzy&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; on twitter. Also be sure to check out &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;bang&lt;/a&gt; for getting stuff done with your team.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;If you&apos;re building a single page app, keep in mind that &amp;#x26;yet offers consulting, training and development services. Shoot Henrik an email (&lt;a href=&quot;mailto:henrik@andyet.net&quot;&gt;henrik@andyet.net&lt;/a&gt;) and tell us what we can do to help.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Backbone.js and Capsule and Thoonk, oh my! A scalable realtime architecture]]></title><description><![CDATA[This last year, we've learned a lot about building scalable realtime web apps, most of which has come from shipping &bang. &bang is the app…]]></description><link>https://blog.andyet.com/2011/11/16/backbonejs-and-capsule-and-thoonk-oh-my-a-scalable/</link><guid isPermaLink="false">https://blog.andyet.com/2011/11/16/backbonejs-and-capsule-and-thoonk-oh-my-a-scalable/</guid><pubDate>Wed, 16 Nov 2011 14:33:04 GMT</pubDate><content:encoded>&lt;p&gt;This last year, we&apos;ve learned a lot about building scalable realtime web apps, most of which has come from shipping &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;bang&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&amp;#x26;bang is the app we use to keep our team in sync. It helps us stay on the same page, bug each other less and just get stuff done as a team.&lt;/p&gt;
&lt;p&gt;The process of actually trying to get something out the door on a bootstrapped budget helped us focus on the most important problems that needed to be solved to build a dynamic, interactive, real-time app in a scaleable way.&lt;/p&gt;
&lt;h3 id=&quot;a-bit-of-history&quot;&gt;&lt;a href=&quot;#a-bit-of-history&quot; aria-label=&quot;a bit of history permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A bit of history&lt;/h3&gt;
&lt;p&gt;I&apos;ve written a couple of posts on backbone.js since discovering it. &lt;a href=&quot;http://andyet.net/blog/2010/oct/29/building-a-single-page-app-with-backbonejs-undersc/&quot;&gt;The first one&lt;/a&gt; introduces &lt;a href=&quot;http://documentcloud.github.com/backbone/&quot;&gt;Backbone.js&lt;/a&gt; as a lightweight client-side framework for building clean, stateful client apps. In &lt;a href=&quot;http://andyet.net/blog/2011/feb/15/re-using-backbonejs-models-on-the-server-with-node/&quot;&gt;the second post&lt;/a&gt; I introduced &lt;a href=&quot;https://github.com/andyet/capsule&quot;&gt;Capsule.js&lt;/a&gt;. Which is a tool that I built on top of Backbone that adds nested models and collections and also allows you to keep a mirror of your client-side state on a node.js server to seemlessly synchronize state between different clients.&lt;/p&gt;
&lt;p&gt;That approach was great for quickly prototyping an app. But as I pointed out in that post, that&apos;s a lot of in memory state being stored on the server and simply doesn&apos;t scale very well.&lt;/p&gt;
&lt;p&gt;At the end of that post I hinted at what we were aiming to do to ultimately solve that problem. So this post is meant to be a bit of an update on those thoughts.&lt;/p&gt;
&lt;h3 id=&quot;our-new-approach&quot;&gt;&lt;a href=&quot;#our-new-approach&quot; aria-label=&quot;our new approach permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Our new approach&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://redis.io&quot;&gt;Redis&lt;/a&gt; is totally freakin&apos; amazing. Period. I can&apos;t say enough good things about it. &lt;a href=&quot;http://twitter.com/antirez&quot;&gt;Salvatore Sanfilippo&lt;/a&gt; is a god among men, in my book.&lt;/p&gt;
&lt;p&gt;Redis can scale.&lt;/p&gt;
&lt;p&gt;Redis can do PubSub.&lt;/p&gt;
&lt;p&gt;PubSub just means events. Just like you can listen for click events in Javascript in a browser you can listen for events in Redis. &lt;/p&gt;
&lt;p&gt;Redis, however is a generic tool. It&apos;s purposely fairly low-level so as to be broadly applicable. &lt;/p&gt;
&lt;p&gt;What makes Redis so interesting, from my perspective, is that you can treat it as a shared memory between processes, languages and platforms. What that means, in a practical sense, is that as long as each app that uses it interacts with it according to a pre-defined set of rules, you can write a whole ecosystem of functionality for an app in whatever language makes the most sense for that particular task.&lt;/p&gt;
&lt;h3 id=&quot;enter-thoonk&quot;&gt;&lt;a href=&quot;#enter-thoonk&quot; aria-label=&quot;enter thoonk permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Enter Thoonk&lt;/h3&gt;
&lt;p&gt;My co-worker, &lt;a href=&quot;http://twitter.com/fritzy&quot;&gt;Nathan Fritz&lt;/a&gt;, is the closest thing you can get to being a veteran of realtime technologies. &lt;/p&gt;
&lt;p&gt;He&apos;s a member of the XSF council for the XMPP standard and probably wrote his first chat bot before you knew what chat was. His &lt;a href=&quot;https://github.com/fritzy/SleekXMPP&quot;&gt;Sleek XMPP&lt;/a&gt; Python library is iconic in the XMPP community. He has a self-declared &lt;em&gt;un-natural&lt;/em&gt; love for &lt;a href=&quot;http://xmpp.org/extensions/xep-0060.html&quot;&gt;XEP-60&lt;/a&gt; which describes the XMPP PubSub standard.&lt;/p&gt;
&lt;p&gt;He took everything he learned from his work on that standard and built &lt;a href=&quot;http://blog.thoonk.com/&quot;&gt;Thoonk&lt;/a&gt;. (In fact, he actually kept the PubSub spec open as he built the Javascript and Python implementations of Thoonk.) &lt;/p&gt;
&lt;h3 id=&quot;what-is-thoonk&quot;&gt;&lt;a href=&quot;#what-is-thoonk&quot; aria-label=&quot;what is thoonk permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What is Thoonk??&lt;/h3&gt;
&lt;p&gt;Thoonk is an abstraction on Redis that provides higher-level datatypes for a more approachable interface. Essentially, staring at Redis as a newbie is a bit intimidating. Not that it&apos;s hard to interface with, it&apos;s just kind of tricky to figure out how to logically structure and retrieve your data. Thoonk simplifies that into a few data-types that describe common use cases. Primarly &quot;feeds&quot;, &quot;sorted feeds&quot;, &quot;queues&quot; and &quot;jobs&quot;. &lt;/p&gt;
&lt;p&gt;You can think of a feed as an ad-hoc database table. They&apos;re &quot;cheap&quot; to create and you simply declare them to make them or use them. For example, in &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;bang&lt;/a&gt;, we have all our users in a feed called &quot;users&quot; for looking up user info. But also, each user has a variety of individual feeds. For example, they have a &quot;task&quot; feed and a &quot;shipped&quot; feed. This is where it veers from what people are used to in a relational database model, because each user&apos;s tasks are not a part of a global &quot;tasks&quot; feed. Instead, each user has a distinct feed of tasks because that&apos;s the entity we want to be able to subscribe to.&lt;/p&gt;
&lt;p&gt;So rather than simply breaking down a model into types of data, we end up breaking things into groups of items (a.k.a. &quot;feeds&quot;) that we want to be able to track changes to. So, as an example, we may have something like this:
&lt;br&gt;
&lt;br&gt;
// our main user feed
var userFeed = thoonk.feed(&apos;users&apos;);
&lt;br&gt;
// an individual task feed for a user
var userTaskFeed = thoonk.sortedFeed(&apos;team.andyet.members.{{memberID}}.tasks&apos;);
&lt;/p&gt;
&lt;h3 id=&quot;marrying-thoonk-and-capsule&quot;&gt;&lt;a href=&quot;#marrying-thoonk-and-capsule&quot; aria-label=&quot;marrying thoonk and capsule permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Marrying Thoonk and Capsule&lt;/h3&gt;
&lt;p&gt;Capsule was actually written with Thoonk in mind. In fact that&apos;s why they were named the way they did: You know these lovely pneumatic tube systems they use to send cash to bank tellers and at Costco? (&lt;strong&gt;PPSHHHHHHH--THOONK!&lt;/strong&gt; And here&apos;s your capsule.)&lt;/p&gt;
&lt;p&gt;Anyway, the integration didn&apos;t end up being quite as tight as we had originally thought but it still works quite well. Loose coupling is better anyway right?&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;core&lt;/em&gt; problem I was trying to solve with Capsule was unifying the models that are used to represent the state of the app in the browser and the models you use to describe your data on the server--ideally, not just unifying the data structure, but also letting me share behavior of those objects. &lt;/p&gt;
&lt;p&gt;Let me explain. &lt;/p&gt;
&lt;p&gt;As I mentioned, we recently shipped &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;bang&lt;/a&gt;. It lets a group of people share their task lists and what they&apos;re actively working on with each other. &lt;/p&gt;
&lt;p&gt;It spares you from a lot of &quot;what are you working on?&quot; conversations and increases accountability by making your work quite public to the team. &lt;/p&gt;
&lt;p&gt;It&apos;s a realtime, keyboard-driven, web app that is designed to &lt;em&gt;feel&lt;/em&gt; like a desktop app. &amp;#x26;bang is a node.js application built entirely with the methods described here.&lt;/p&gt;
&lt;p&gt;So, in &amp;#x26;bang, a team model has attributes as well as a couple of nested backbone collections such as members and chat messages. Each member has attributes and other nested collections, tasks, shipped items, etc.&lt;/p&gt;
&lt;h3 id=&quot;initial-state-push&quot;&gt;&lt;a href=&quot;#initial-state-push&quot; aria-label=&quot;initial state push permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Initial state push&lt;/h3&gt;
&lt;p&gt;When a user first logs in we have to send the entire model state for the team(s) they&apos;re on so we can build out the interface (see my previous post for more on that). So, the first thing we do when a user logs in is subscribe them to the relevant Thoonk feeds and perform the the initial state transfer to the client.&lt;/p&gt;
&lt;p&gt;To do this, we init an empty team model on the client (a backbone/capsule model shared between client/server) . Then we recurse through our Thoonk feed structures on the server to export the data from the relevant feeds into a data structure that Capsule can use to import that data. The team model is inflated with the data from the server and we draw the interface. &lt;/p&gt;
&lt;p&gt;From there, the application is kept in sync using events from Thoonk that get sent over websockets and applied to the client interface. Events like &quot;publish&quot;, &quot;change&quot;, &quot;retract&quot; and &quot;position&quot;. &lt;/p&gt;
&lt;p&gt;Once we got the app to the point where this was all working, it was kind of a magical moment, because at this point, any edits that happen in Thoonk will simply get pushed out through the event propagation all the way to the client. Essentially, the inteface that a user sees is largely a slave to the server. Except, of course, the portions of state that we let the user manipulate locally. &lt;/p&gt;
&lt;p&gt;At this point, user interactions with the app that change data are all handled through RPC calls. Let&apos;s jump back to the server and you&apos;ll see what I mean.&lt;/p&gt;
&lt;h3 id=&quot;i-thought-you-were-still-using-capsule-on-the-server&quot;&gt;&lt;a href=&quot;#i-thought-you-were-still-using-capsule-on-the-server&quot; aria-label=&quot;i thought you were still using capsule on the server permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;I thought you were still using Capsule on the server?&lt;/h3&gt;
&lt;p&gt;We do, but differently, here&apos;s how that is handled. &lt;/p&gt;
&lt;p&gt;In short... it&apos;s a job system.&lt;/p&gt;
&lt;p&gt;Sounds intimidating right? As someone who started in business school, then gradually got into front-end dev, then back-end dev, then a pile of JS, job systems sounded scary. In my mind they&apos;re for &quot;hardcore&quot; programmers like &lt;a href=&quot;http://twitter.com/fritzy&quot;&gt;Fritzy&lt;/a&gt; or &lt;a href=&quot;http://twitter.com/natevw&quot;&gt;Nate&lt;/a&gt; or &lt;a href=&quot;http://twitter.com/lancestout&quot;&gt;Lance&lt;/a&gt; from our team. Job systems don&apos;t have to be that scary.&lt;/p&gt;
&lt;p&gt;At a very high level you can think of a &quot;job&quot; as a function call. The key difference being, you don&apos;t necessarily expect an immediate result. To continue with examples from &amp;#x26;bang: a job may be to &quot;ship a task&quot;. So, what do we need to know to complete that action? We need the following: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;member Id of the user shipping the task&lt;/li&gt;
&lt;li&gt;the task id being completed (we call this &quot;shipping&quot;, because it&apos;s cooler, and it&apos;s a reminder a reminder that finishing is what&apos;s important)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can derive everything else we need from those key pieces of information.&lt;/p&gt;
&lt;p&gt;So, rather than call a function somewhere:
&lt;br&gt;
&lt;br&gt;
shipTask(memberId, taskId)
&lt;/p&gt;
&lt;p&gt;We can just describe a job as a simple JSON object:
&lt;br&gt;
&lt;br&gt;
{
userId: &lt;user requesting the job&gt;,
taskId: &amp;#x3C;id of task to &apos;ship&apos;&gt;,
memberId: &lt;id of team member&gt;
}
&lt;/p&gt;
&lt;p&gt;The we can add that to our &quot;shipTask&quot; job queue like so:
&lt;br&gt;
&lt;br&gt;
thoonk.job(&apos;shipTask&apos;).put(JSON.stringify(jobObject));
&lt;/p&gt;
&lt;p&gt;The cool part about the event propagation I talked about above is we really don&apos;t care so much when that job gets done. Obviously fast is key, but what I mean is, we don&apos;t have to sit around and wait for a synchronous result because the event propagation we&apos;ve set up will handle all the application state changes.&lt;/p&gt;
&lt;p&gt;So, now we can write a worker that listens for jobs from that job queue. In that worker we&apos;ll perform all the necessary related logic. Specifically stuff like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Validating that the job is properly formatted (contains required fields of the right type)&lt;/li&gt;
&lt;li&gt;Validating that the user is the owner of that task and is therefore allowed to &quot;ship&quot; it.&lt;/li&gt;
&lt;li&gt;Modifying Thoonk feeds accordingly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;encapsulating-and-reusing-model-logic&quot;&gt;&lt;a href=&quot;#encapsulating-and-reusing-model-logic&quot; aria-label=&quot;encapsulating and reusing model logic permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Encapsulating and reusing model logic&lt;/h3&gt;
&lt;p&gt;You&apos;ll notice that part of that list requires some logic. Specifically, checking to see if the user requesting the action is allowed to perform it. We could certainly write that logic right here, in this worker. But, in the client we&apos;re also going to want to know if a user is allowed to ship a given task, right? Why write that logic twice? &lt;/p&gt;
&lt;p&gt;Instead we write that logic as a method of a Capsule model that describes a task. Then, we can use the same method to determine whether to show the UI that lets the user perform the action in the browser as we use on the back end to actually perform the validation. We do that by re-inflating a Capsule model for that task in our worker code and calling the &lt;code class=&quot;language-text&quot;&gt;canEdit()&lt;/code&gt; method on it and passing it the user id requesting the action. The only difference being, on the server-side we don&apos;t trust the user to tell us who they are. On the server we roll the user id we have for that session into the job when it&apos;s created rather then trust the client.&lt;/p&gt;
&lt;h3 id=&quot;security&quot;&gt;&lt;a href=&quot;#security&quot; aria-label=&quot;security permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Security&lt;/h3&gt;
&lt;p&gt;One other, hugely important thing that we get by using Capsule models on the server is some security features. There are some model attributes that are read only as far a the client is concerned. What if we get a job that tries to edit a user&apos;s ID? In a backbone model if I call:
&lt;br&gt;
&lt;br&gt;
backboneModelInstance.set({id: &apos;newId&apos;});
&lt;/p&gt;
&lt;p&gt;That will change the ID of the object. Clearly that&apos;s not good in a server environment when you&apos;re trusting that to be a unique ID. There are also lots of other fields you may want on the client but you don&apos;t want to let users edit. &lt;/p&gt;
&lt;p&gt;Again, we can encapsulate that logic in our Capsule models. Capsule models have a &lt;code class=&quot;language-text&quot;&gt;safeSet&lt;/code&gt; method that assumes all inputs are evil. Unless an attribute is whitelisted as &lt;code class=&quot;language-text&quot;&gt;clientEditable&lt;/code&gt; it won&apos;t set it. So when we go to set attributes within the worker on the server we use &lt;code class=&quot;language-text&quot;&gt;safeSet&lt;/code&gt; when dealing with untrusted input.&lt;/p&gt;
&lt;p&gt;The other important piece of securing a system that lets users indirectly add jobs to your job system is ensuring that the job you receive validate your schema. I&apos;m using a node implementation of JSON Schema for this. I&apos;ve heard some complaints about that proposed standard, but it works really well for the fairly simple usecase I need it for. &lt;/p&gt;
&lt;p&gt;A typical worker may look something like this:
&lt;br&gt;
&lt;br&gt;
workers.editTeam = function () {
var schema = {
type: &quot;object&quot;,
properties: {
user: {
type: &apos;string&apos;,
required: true
},
id: {
type: &apos;string&apos;,
required: true
},
data: {
type: &apos;object&apos;,
required: true
}
}
};
&lt;br&gt;
editTeamJob.get(0, function (err, json, jobId, timeout) {
var feed = thoonk.feed(&apos;teams&apos;),
result,
team,
newAttributes,
inflated;
&lt;br&gt;
async.waterfall([
function (cb) {
// validate our job
validateSchema(json, schema, cb);
},
function (clean, cb) {
// store some variables from our cleaned job
result = clean;
team = result.id;
newAttributes = result.data;
verifyOwnerTeam(team, cb);
},
function (teamData, cb) {
// inflate our capsule model
inflated = new Team(teamData);
// if from the server user normal &apos;set&apos;
inflated.safeSet(newAttributes);
},
function (cb) {
// do the edit, all we&apos;re doing is storing JSON strings w/ ids
feed.edit(JSON.stringify(inflated.toJSON()), result.id, cb);
}
], function (err) {
var code;
if (!err) {
code = 200;
logger.info(&apos;edited team&apos;, {team: team, attrs: newAttributes});
} else if (err === &apos;notAllowed&apos;) {
code = 403;
logger.warn(&apos;not allowed to edit&apos;);
} else {
code = 500;
logger.error(&apos;error editing team&apos;, {err: err, job: json});
}
// finish the job
editTeamJob.finish(jobId, null, JSON.stringify({code: code}));
// keep the loop crankin&apos;
process.nextTick(workers.editTeam);
});
});
};
&lt;/p&gt;
&lt;h3 id=&quot;sounds-like-a-lot-of-work&quot;&gt;&lt;a href=&quot;#sounds-like-a-lot-of-work&quot; aria-label=&quot;sounds like a lot of work permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Sounds like a lot of work&lt;/h3&gt;
&lt;p&gt;Granted, writing a worker for each type of action a user can perform in the app with all the related job and validation is not an insignificant amount of work. However, it worked rather well for us to use the state syncing stuff in Capsule while we were still in the prototyping stage, then converting the server-side code to a Thoonk-based solution when we were ready to roll out to production.&lt;/p&gt;
&lt;h3 id=&quot;so-why-does-any-of-this-matter&quot;&gt;&lt;a href=&quot;#so-why-does-any-of-this-matter&quot; aria-label=&quot;so why does any of this matter permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So why does any of this matter?&lt;/h3&gt;
&lt;p&gt;It works. &lt;/p&gt;
&lt;p&gt;What this ultimately means is that we now push the system until Redis is our bottleneck. We can spin up as many workers as we want to crank through jobs and we can write those workers in any language we want. We can put our node app behind HA proxy or Bouncy and spin up a bunch of &apos;em. Do we have all of this solved and done? No. But the core ideas and scaling paths seem fairly clear and doable. &lt;/p&gt;
&lt;p&gt;[update: Just to add a bit more detail here, from our tests we feel confident that we can scale to tens of thousands of users on a single server and we believe we can scale vertically after doing some intelligent sharding with multiple servers.]&lt;/p&gt;
&lt;h3 id=&quot;is-this-the-rails-of-realtime&quot;&gt;&lt;a href=&quot;#is-this-the-rails-of-realtime&quot; aria-label=&quot;is this the rails of realtime permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Is this the &quot;Rails of Realtime?&quot;&lt;/h3&gt;
&lt;p&gt;Nope. &lt;/p&gt;
&lt;p&gt;Personally, I&apos;m not convinced there ever will be one. Even Owen Barnes (who originally set out to build just that with SocketStream) said at &lt;a href=&quot;http://krtconf.com&quot;&gt;KRTConf&lt;/a&gt;: &quot;There will not be a black box type framework for realtime.&quot; His new approach is to build a set of interconnected modules for structuring out a realtime app based on the unique needs of its specific goals.&lt;/p&gt;
&lt;p&gt;The kinds of web apps being built these days don&apos;t fit into a neat little box. We&apos;re talking to multiple web services, multiple databases, and pushing state to the client. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://twitter.com/mikeal&quot;&gt;Mikeal Rogers&lt;/a&gt; gave a great talk at KRTConf about that exact problem. It&apos;s going to be really, really hard to create a framework that solves all those problems in the same way that Rails or Django can solve 90% of the common problems with routes and MVC.&lt;/p&gt;
&lt;h3 id=&quot;can-you-support-a-bajillion-users&quot;&gt;&lt;a href=&quot;#can-you-support-a-bajillion-users&quot; aria-label=&quot;can you support a bajillion users permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Can you support a BAJILLION users?&lt;/h3&gt;
&lt;p&gt;No, but a single Redis db can handle a fairly ridiculous amount of users. At the point that actually becomes our bottleneck, (1) we can split out different feeds for different databases, and (2) we&apos;d have a user base that would make the app wildly profitable at that point--certainly more than enough to spend some more time on engineering. What&apos;s more, Salvatore and the Redis team are putting a lot of work into clustering and scaling solutions for Redis that very well may outpace our need for sharding, etc.&lt;/p&gt;
&lt;h3 id=&quot;have-you-thought-about-x-y-z&quot;&gt;&lt;a href=&quot;#have-you-thought-about-x-y-z&quot; aria-label=&quot;have you thought about x y z permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Have you thought about X, Y, Z?&lt;/h3&gt;
&lt;p&gt;Maybe not! The point of this post is simply to share what we&apos;ve learned so far. &lt;/p&gt;
&lt;p&gt;You&apos;ll notice this isn&apos;t a &quot;use our new framework&quot; post. We would still need to do a lot of work to cleanly extract and document a complete realtime app solution from what we&apos;ve done in &amp;#x26;bang--particularly if we were trying to provide a tool that can be used to quickly spin up an app. If your goal is to find a tool like that, definitely check out what Owen and team are doing with &lt;a href=&quot;https://github.com/socketstream/socketstream&quot;&gt;SocketStream&lt;/a&gt; and what Nate and Brian are doing with &lt;a href=&quot;http://derbyjs.com&quot;&gt;Derby&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We love the web, and love the kinds of apps that can be built with modern web technologies. It&apos;s our hope that by sharing what we&apos;ve done, we can push things forward. If you find this post helpful, we&apos;d love your feedback.&lt;/p&gt;
&lt;p&gt;Technology is just a tool, ultimately, it&apos;s all about building cool stuff. Check out &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;bang&lt;/a&gt; and follow me &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt;, Adam &lt;a href=&quot;http://twitter.com/adambrault&quot;&gt;@AdamBrault&lt;/a&gt; and the whole &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; team on the twitterwebz.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;If you&apos;re building a single page app, keep in mind that &amp;#x26;yet offers consulting, training and development services. Hit us up (&lt;a href=&quot;mailto:henrik@andyet.net&quot;&gt;henrik@andyet.net&lt;/a&gt;) and tell us what we can do to help.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[We shipped an app that requires WebSockets. Here's why:]]></title><description><![CDATA[Last week we launched our newest product, &!, at KRTConf. It's a realtime, single-page app that empowers teams to bug each other less and…]]></description><link>https://blog.andyet.com/2011/11/14/we-shipped-an-app-that-requires-websockets-heres-w/</link><guid isPermaLink="false">https://blog.andyet.com/2011/11/14/we-shipped-an-app-that-requires-websockets-heres-w/</guid><pubDate>Mon, 14 Nov 2011 20:57:33 GMT</pubDate><content:encoded>&lt;p&gt;Last week we launched our newest product, &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;!&lt;/a&gt;, at &lt;a href=&quot;http://krtconf.com&quot;&gt;KRTConf&lt;/a&gt;. It&apos;s a realtime, single-page app that empowers teams to bug each other less and get more done as a team.&lt;/p&gt;
&lt;p&gt;One of our speakers, &lt;a href=&quot;http://twitter.com/shanselman&quot;&gt;Scott Hanselman&lt;/a&gt; from Microsoft tried to open the app in IE9 and was immediately redirected to a page that tells users they need WebSockets to use the app. He then &lt;a href=&quot;http://www.hanselman.com/blog/CommentView.aspx?guid=45b744bd-635d-4059-8f90-676ed718b39e&quot;&gt;wrote a post&lt;/a&gt; criticizing this choice, his argument being that users don&apos;t care about the underlying technology, they just want it to work. He thinks we should provide reasonable fallbacks so that it works for as wide of an audience as possible.&lt;/p&gt;
&lt;p&gt;I completely agree with his basic premise: users don&apos;t care about the technology.&lt;/p&gt;
&lt;p&gt;Users care about their experience. &lt;/p&gt;
&lt;p&gt;I think this is something the web has ignored for far too long so I&apos;ll say it again:&lt;/p&gt;
&lt;p&gt;Users &lt;em&gt;only&lt;/em&gt; care about their experience.&lt;/p&gt;
&lt;p&gt;In this case, we&apos;re not building a website with content. We&apos;re building an experience. &lt;/p&gt;
&lt;p&gt;We didn&apos;t require Web Sockets because we&apos;re enamored with the technology, we actually require it precisely because it provides the best user experience.&lt;/p&gt;
&lt;p&gt;The app simply doesn&apos;t feel as responsive when long-polling. There&apos;s enough of a difference in lag and responsiveness that we made the choice to eliminate the other available transports in Socket.io. (We&apos;re doing a lot more with our data transport than simply sending chats.) Additionally, we&apos;re also using advanced HTML5 and CSS3 that simply isn&apos;t available yet in IE9. It turns out that checking for WebSockets is a fairly good litmus test of the support of those other features (namely CSS3 transitions and animations). The app is just plain more fun to use because of those features.&lt;/p&gt;
&lt;p&gt;Apple beat Microsoft by focusing on user experience. They unapologetically enforced minimum system requirements and made backward incompatible changes. Why is it considered &quot;acceptable&quot; to require minimum hardware (which costs money), but it&apos;s somehow not acceptable to require users to download a free browser?&lt;/p&gt;
&lt;p&gt;I&apos;ve said this over and over again: web developers who are building single-page applications are in &lt;em&gt;direct&lt;/em&gt; competition with native applications.&lt;/p&gt;
&lt;p&gt;If we as web developers continue to limp along support for less-than-top-notch browsers, the web will continue to lose ground to the platforms that build for user experience first. Why should we, as a small bootstrapped company invest our limited resources building less-than-ideal fallbacks?&lt;/p&gt;
&lt;p&gt;All this, of course, depends on your audience. We created &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;!&lt;/a&gt; for small, forward-thinking teams, not necessarily their moms. :)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[An interview with Amber Case, cyborg anthropologist and software futurist]]></title><description><![CDATA[Our &yet team were privileged to get to sit down and chat with one of the young visionaries of modern software, Amber Case, Cyborg…]]></description><link>https://blog.andyet.com/2011/11/02/an-interview-with-amber-case-cyborg-anthropologist/</link><guid isPermaLink="false">https://blog.andyet.com/2011/11/02/an-interview-with-amber-case-cyborg-anthropologist/</guid><pubDate>Wed, 02 Nov 2011 15:59:36 GMT</pubDate><content:encoded>&lt;iframe src=&quot;https://player.vimeo.com/video/31451941?title=0&amp;byline=0&amp;portrait=0&quot; height=&quot;287&quot; width=&quot;510&quot; allowfullscreen webkitallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Our &amp;#x26;yet team were privileged to get to sit down and chat with one of the young visionaries of modern software, Amber Case, Cyborg Anthropologist and Geoloqi founder. &lt;/p&gt;
&lt;p&gt;Thanks to Pie and Wieden+Kennedy. &lt;/p&gt;
&lt;p&gt;Music by Dat&apos;r &lt;/p&gt;
&lt;p&gt;Film by Melanie Brown &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Parenting with CSS4. And vengeance. A very special Vodcast.]]></title><description><![CDATA[It's our first podcast, or maybe &cast, and what a start we're off to.James displays a knack for not preparing, being distracted, and wiping…]]></description><link>https://blog.andyet.com/2011/10/25/parenting-with-css4-and-vengeance-a-very-special-v/</link><guid isPermaLink="false">https://blog.andyet.com/2011/10/25/parenting-with-css4-and-vengeance-a-very-special-v/</guid><pubDate>Tue, 25 Oct 2011 10:28:32 GMT</pubDate><content:encoded>&lt;p&gt;It&apos;s our first podcast, or maybe &amp;#x26;cast, and what a start we&apos;re off to.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://twitter.com/jamesmenera&quot;&gt;James&lt;/a&gt; displays a knack for not preparing, being distracted, and wiping sweat off his face. He does, however, know what he&apos;s talking about when it comes to CSS specs. Eric asks James to explain the newly proposed subject selectors, link psuedo-classes and whether or not anyone could become Batman, realistically.&lt;/p&gt;
&lt;p&gt;Let us know what you think about the CSS4 proposals and how excited you are about the &quot;parent&quot; selector. Because as you can tell, we&apos;re wicked excited about it over here.&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/30884167?title=0&amp;byline=0&amp;portrait=0&quot; height=&quot;287&quot; width=&quot;510&quot; allowfullscreen webkitallowfullscreen frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Credits:&lt;/p&gt;
&lt;p&gt;&quot;Talent&quot;: &lt;a href=&quot;http://twitter.com/ericzanol&quot;&gt;@ericzanol&lt;/a&gt; (left) and &lt;a href=&quot;http://twitter.com/jamesmenera&quot;&gt;@jamesmenera&lt;/a&gt; (right).&lt;/p&gt;
&lt;p&gt;Video filmed and produced by the awesome Ms. &lt;a href=&quot;/team/melanie/&quot;&gt;Mel&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Unsafe at certain speeds: dangers designed into Django]]></title><description><![CDATA[A good software development framework should make the common things easy and make the uncommon things possible.Unfortunately, Django…]]></description><link>https://blog.andyet.com/2011/09/20/unsafe-at-certain-speeds-dangers-designed-into-dja/</link><guid isPermaLink="false">https://blog.andyet.com/2011/09/20/unsafe-at-certain-speeds-dangers-designed-into-dja/</guid><pubDate>Tue, 20 Sep 2011 12:13:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1d528e2cb5fbc29ad16c74e5d883c371/c1b63/django-logo-negative.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 45.6953642384106%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAAsSAAALEgHS3X78AAABxElEQVQoz2Pg1FMAIg49BUYVURBSFuHUV4QIEkQMEIpdRy40LzUgKyGyKINZU4pFSxoiyKwpzaErz62vyAZjAxksWjJcYAtAmpk0pFTdLE9cOFs7sTOnqUrYXFPF1QIoLWiqrupmxWOozKAqJmaprehszmekImqhreBkCrQApJlRXaK8p+X8tSvX79xumzGxY9bktJqSWw/uNU7p3bBn+9U7N2evWhqSl3zw1PGHz55OWDBr076dV27fSKwoYFARZRAwUbt255Z7UsTq7ZsXrF+5ctvGks7GQ2dOrNqxCegW77SYizevXbh+Jbm6aN7a5UfOnuqZOy22NGfnkQMMauIMQAdMWTzv2LnTxy+c6Vswc8OeHXuPHz575eK8dSuADPfkiH3HD/fOn7Hn6KHz1y7X9HfsO37k5MVzJR2NDMqiDMBQAbreJspP28t+68E9ExbO4jNW9UyJVnA0VXO3Avpf3cPaPiYQ6Ivnr18qOJpoeto6xgazaskgQptBVZxDRy6qOEvGzgjkHlUxoDQwzIHBy6AmUdhat2731oSKfGA4s2hKM6qJc8JDG4igQa8kwq4tC2TDEUQWGEmsQD0qohCVcHEA3qGtOtaTV/gAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;django logo&quot;
        title=&quot;&quot;
        src=&quot;/static/1d528e2cb5fbc29ad16c74e5d883c371/90cbd/django-logo-negative.png&quot;
        srcset=&quot;/static/1d528e2cb5fbc29ad16c74e5d883c371/29fe9/django-logo-negative.png 151w,
/static/1d528e2cb5fbc29ad16c74e5d883c371/6728c/django-logo-negative.png 303w,
/static/1d528e2cb5fbc29ad16c74e5d883c371/90cbd/django-logo-negative.png 605w,
/static/1d528e2cb5fbc29ad16c74e5d883c371/a2b88/django-logo-negative.png 908w,
/static/1d528e2cb5fbc29ad16c74e5d883c371/c1b63/django-logo-negative.png 1200w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A good software development framework should make the common things easy and make the uncommon things possible.&lt;/p&gt;
&lt;p&gt;Unfortunately, Django sometimes makes the &lt;em&gt;simple&lt;/em&gt; things easy and the hard things possible — and security is hard!&lt;/p&gt;
&lt;h3 id=&quot;what-django-does-well&quot;&gt;&lt;a href=&quot;#what-django-does-well&quot; aria-label=&quot;what django does well permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Django does well&lt;/h3&gt;
&lt;p&gt;The Django community does take security very seriously.&lt;/p&gt;
&lt;p&gt;The ORM makes it really difficult to expose your app to SQL injection attacks. The template processing system makes it hard to enable cross-site scripting. It takes work to avoid Django&apos;s CSRF protection, and it&apos;d be rare to subvert its well-tested session handling.&lt;/p&gt;
&lt;p&gt;Not only that, but Django&apos;s documentation and release notes go the extra mile, discouraging many poor practices and even warning against problems outside of Django that could affect the security of a web app.&lt;/p&gt;
&lt;h3 id=&quot;djangos-target-market&quot;&gt;&lt;a href=&quot;#djangos-target-market&quot; aria-label=&quot;djangos target market permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Django&apos;s target market&lt;/h3&gt;
&lt;p&gt;So what&apos;s the problem?&lt;/p&gt;
&lt;p&gt;Django has its roots in the publishing industry and got its wings as a basis for sharing-oriented &quot;Web 2.0&quot; sites. When a majority of resources are publicly available, or shared among all logged-in users, it&apos;s possible to focus on securing a few private corners.&lt;/p&gt;
&lt;p&gt;What Django&apos;s design considers uncommon is &quot;multitenant&quot; apps — imagine that instead of adding a blog to your company website, you are building a corporate blog–hosting &lt;em&gt;service&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;With a single-tenant app, there&apos;s generally some level of trust among all users. Maybe an intern is only supposed to edit customer support documents, but discovers a bug in the custom CMS built on Django that lets him post a funny picture of his boss on the homepage. Sure it was &lt;strong&gt;technically&lt;/strong&gt; the Django-using programmer who let it happen, but it was the intern who betrayed the tenant&apos;s trust.&lt;/p&gt;
&lt;p&gt;With multiple tenants, the responsibility of trust &lt;strong&gt;is&lt;/strong&gt; upon the developers. When some computer-savvy ACME Corp employees find a hole that lets them access Wonder Inc&apos;s draft blog posts, they&apos;re just doing their job. If Wonder Inc imagined their exciting product announcements were safe inside your Django app, they won&apos;t care how easy it was to make that security mistake.&lt;/p&gt;
&lt;h3 id=&quot;what-django-makes-easy&quot;&gt;&lt;a href=&quot;#what-django-makes-easy&quot; aria-label=&quot;what django makes easy permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What Django makes easy&lt;/h3&gt;
&lt;p&gt;Most days, most developers are struggling valiantly just to get their code to &lt;em&gt;work&lt;/em&gt;. Getting it to &quot;compile&quot;, getting it to &quot;run&quot;, getting it to run &quot;on the production database&quot;. Fixing it to stay running even when a user clicks Y &lt;em&gt;before&lt;/em&gt; they click X.&lt;/p&gt;
&lt;p&gt;Security is hard because you still have to do all the &quot;just getting it to work&quot;, but you &lt;em&gt;also&lt;/em&gt; have to make sure it &lt;em&gt;doesn&apos;t&lt;/em&gt; work even if a &lt;em&gt;different&lt;/em&gt; user clicks X, fakes Y and then does Z with a little help from A.&lt;/p&gt;
&lt;p&gt;Let me make this clear: security mistakes are too common to be a problem of &quot;stupid developers&quot;. Leave the PEBKAC mentality for the poor techs who have to support what they can&apos;t fix — we are developers and designers, busy developing our designs. Engineering, Enforcement and Education are wonderful, but usability is cheaper.&lt;/p&gt;
&lt;p&gt;Django&apos;s ORM makes it easy — too easy — to expose database rows to users who shouldn&apos;t have access. It provides a very user-friendly mapping from SQL to model objects. The catch is, the database doesn&apos;t give a rat&apos;s rooty-tooty about your app&apos;s permission model, and neither does the ORM. Its job is to be the floppy disk for your spreadsheets, the ORM&apos;s job is to pretend the spreadsheet rows are documents. Fair enough. But the tools Django provides for validating data access are too difficult to customize for an app where every table is shared among mutually untrusted tenants. Remember that developers are naturally inclined to code until it works for them — not to prove that the same code won&apos;t work when an attacker calls it up.&lt;/p&gt;
&lt;p&gt;The template processing and file handling infrastructure encourage developers to expose private user uploads via statically hosted media directories. This is fine for a blog, but when a user notices their private upload got renamed to &quot;/media/user_images/image&lt;strong&gt;___&lt;/strong&gt;.jpg&quot; they might start figuring out that Apache will gladly let them see &quot;image___.jpg&quot; (and &lt;a href=&quot;http://www.scribd.com/doc/37121628/nGenuity-Djangocon2010-Pony-Pwning&quot;&gt;&quot;image.php&quot;&lt;/a&gt;!) in that directory too.&lt;/p&gt;
&lt;p&gt;Finally, while most of Django&apos;s middleware does enhance web app security, the error debugging system can lead to inadvertent storage of sensitive user data if an exception catches it mid-flight. This issue is being addressed for Django 1.4, although the design is opt-in and may be a bit fragile in practice — but this particular problem &lt;em&gt;is&lt;/em&gt; both hard and uncommon. In this last case I suspect the solution being built in is a good enough design.&lt;/p&gt;
&lt;h3 id=&quot;how-to-make-secure-apps-more-common&quot;&gt;&lt;a href=&quot;#how-to-make-secure-apps-more-common&quot; aria-label=&quot;how to make secure apps more common permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to make secure apps more common&lt;/h3&gt;
&lt;p&gt;That leaves us with Django&apos;s ORM and file handling — which I&apos;m convinced are &lt;em&gt;not&lt;/em&gt; good enough designs for a multitenant web app framework.&lt;/p&gt;
&lt;p&gt;In a multitenant app it is very common that model lookups and form validation must be contained to a stricter subset of data than Django encourages.&lt;/p&gt;
&lt;p&gt;The very best solution to this problem is to &lt;strong&gt;partition your app&lt;/strong&gt;. Give each tenant their own virtual system, their own database — in short, their own copy of the hosted app.Partitioning does take more work to configure up-front, but that&apos;s the best place for investments like that. It also complicates cross-account administration features: which is exactly the point. Make the uncommon use cases the harder ones, so that the normal stuff is securer by default.&lt;/p&gt;
&lt;p&gt;If you&apos;re not ready or it&apos;s too late to partition, do your whole team a favor and stop using Django&apos;s ORM and ModelForms directly in a multitenant codebase. You need to &lt;strong&gt;write an API&lt;/strong&gt; and force all your code to use it, instead of the ORM. Django&apos;s views are too presentation-focused. &lt;em&gt;Not&lt;/em&gt; the place to expect secure code. When coding up a working user interface, it&apos;s too easy to say &quot;&lt;em&gt;My code&lt;/em&gt; needs this object!&quot; when you mean &quot;&lt;em&gt;Some user&lt;/em&gt; would like to access this data?&quot;. Give day-to-day development the freedom to wholeheartedly fight For the user. Build an internal Python data access API for the sole purpose of standing between the &lt;em&gt;user request&lt;/em&gt; and the ORM or filesystem; a good gate on this border &lt;em&gt;can&lt;/em&gt; keep a thousand welcome mats safe.&lt;/p&gt;
&lt;p&gt;Whether you partition your app into single-tenant instances or use an API to isolate data access, you should develop &lt;strong&gt;tests primarily for security&lt;/strong&gt;. If a commit breaks functionality, it&apos;s an obvious bug. Someone will complain soon enough. If a code change only adds &quot;functionality&quot; that isn&apos;t supposed to exist, it&apos;s a zero-day. Will you notice the mistake in time?&lt;/p&gt;
&lt;p&gt;Interestingly enough, our security tests do tend to catch functionality regressions too, since they really must check that Mallory can&apos;t do something Alice and Bob &lt;em&gt;can&lt;/em&gt;.That&apos;s a nice benefit, especially since you&apos;re still updating tests because the app is getting better and its security needs to as well. (Having to maintain tests that only lock in functionality as it continually changes, sucks.)&lt;/p&gt;
&lt;p&gt;Focus your programmatic testing efforts on permissions enforcement. Your time is precious — don&apos;t bother with automated tests for anything less valuable than earning trust!&lt;/p&gt;
&lt;h3 id=&quot;make-boring-mistakes-hard&quot;&gt;&lt;a href=&quot;#make-boring-mistakes-hard&quot; aria-label=&quot;make boring mistakes hard permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Make boring mistakes hard&lt;/h3&gt;
&lt;p&gt;Django is a great traditional web framework that makes many customizations easy. It&apos;s possible to build secure multitenant apps using the pieces Django provides, although certain built-in features and certain patterns encouraged by the documentation need to be avoided.&lt;/p&gt;
&lt;p&gt;I suspect this is also the case with many other web frameworks. And security might not be the only area where developers&apos; toolkits make doing things &quot;the wrong way&quot; the easy way.&lt;/p&gt;
&lt;p&gt;Pay attention to design decisions at the framework level that distract your team from delivering a great user experience at a higher level.&lt;/p&gt;
&lt;p&gt;Avoid shooting yourselves in the foot (feets?) by only picking fights on fronts where the troops will stay engaged. Make solving interesting problems the only uphill battle for your developers. Then level the field for your customers. (That&apos;s what usability is about.)&lt;/p&gt;
&lt;p&gt;To see us work it&apos;s not self-evident, but nerds invented computers to &lt;em&gt;avoid&lt;/em&gt; tedious mistake-prone work. Like end-users, developers have lives and are busy and are experts only in &lt;em&gt;their own&lt;/em&gt; passions. Assume security will be taken for granted by users, and developers alike!&lt;/p&gt;
&lt;p&gt;If secure web apps should be common, vulnerable code must be made hard to write. It is a good workman&apos;s responsibility to blame his tools every now and then — occasionally we get something as useful as Django as a result!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[A cross-communal conference all about realtime technology – for developers by developers]]></title><description><![CDATA[Realtime is becoming a central part of Internet technology.It's sneaking it's way into our lives already with push notifications, Facebook…]]></description><link>https://blog.andyet.com/2011/08/09/a-cross-communal-conference-all-about-realtime-tec/</link><guid isPermaLink="false">https://blog.andyet.com/2011/08/09/a-cross-communal-conference-all-about-realtime-tec/</guid><pubDate>Tue, 09 Aug 2011 08:58:51 GMT</pubDate><content:encoded>&lt;p&gt;Realtime is becoming a central part of Internet technology.&lt;/p&gt;
&lt;p&gt;It&apos;s sneaking it&apos;s way into our lives already with push notifications, Facebook and Google&apos;s web chats, and it&apos;s a core focus for startups like &lt;a href=&quot;http://convore.com&quot;&gt;Convore&lt;/a&gt;, &lt;a href=&quot;http://pusherapp.com&quot;&gt;Pusher&lt;/a&gt;, &lt;a href=&quot;http://superfeedr.com&quot;&gt;Superfeedr&lt;/a&gt;, &lt;a href=&quot;http://browserling.com&quot;&gt;Browserling&lt;/a&gt;, &lt;a href=&quot;http://nowjs.com/&quot;&gt;NowJS&lt;/a&gt;, &lt;a href=&quot;http://urbanairship.com&quot;&gt;Urban Airship&lt;/a&gt;, &lt;a href=&quot;http://learnboost.com&quot;&gt;Learnboost&lt;/a&gt;, our own &amp;#x26;&lt;a href=&quot;http://andbang.com&quot;&gt;! (andbang)&lt;/a&gt;, and many more.&lt;/p&gt;
&lt;p&gt;What&apos;s most interesting to me is how accessible this is all becoming for developers. In my presentation at NodeConf I mentioned that the adoption of new technology seems directly related to how easy it is to tinker with it. So, as realtime apps get easier and easier to build, I&apos;m convinced that we&apos;re going to see a whole slew of new applications that tap this power in new, amazing ways.&lt;/p&gt;
&lt;p&gt;We at &amp;#x26;yet have built five or so realtime apps in the past year, and we&apos;re super excited about this stuff. We&apos;ve also discovered that there are a slew of different methods and tools for building these kinds of apps--we&apos;ve used a number of them. Different developer communities have been solving the same problems with different tools and it&apos;s been amazing to see how much mindblowingly awesome code has been so freely shared. However, there&apos;s still a bit of a disconnect, because it often happens within a given dev community. We always find that we learn the most when we talk to and learn from people who are doing things differently than we are.&lt;/p&gt;
&lt;p&gt;So what can we do to encourage more of this?&lt;/p&gt;
&lt;p&gt;That&apos;s exactly the conversation &lt;a href=&quot;http://twitter.com/adambrault&quot;&gt;Adam&lt;/a&gt; and I were having when we went to the XMPP Summit in Brussels, Belgium. That conversation culminated into an outrageous idea: We should put on a conference entirely focused on realtime web stuff!&lt;/p&gt;
&lt;p&gt;It&apos;s outrageous, for a couple of reasons. First, we&apos;ve never organized a conference before and secondly we&apos;re in Eastern Washington, not exactly a tech hotspot (although, we&apos;re &lt;a href=&quot;http://www.meetup.com/doctype-society/&quot;&gt;working&lt;/a&gt; &lt;a href=&quot;http://tumbleweed.it&quot;&gt;on&lt;/a&gt; &lt;a href=&quot;http://triconf.com&quot;&gt;that&lt;/a&gt; too). Luckily we&apos;re fortunate to have made some awesome friends as we&apos;ve attended conferences, written blogposts and worked on pretty cool projects for our clients.&lt;/p&gt;
&lt;p&gt;We&apos;re teaming up with &lt;a href=&quot;http://twitter.com/julien51&quot;&gt;Julien Genestoux&lt;/a&gt; and &lt;a href=&quot;http://superfeedr.com&quot;&gt;Superfeedr&lt;/a&gt; to make this all happen. Julien is a pioneer and incredible visionary when it comes to realtime technology. Superfeedr was one of the early startups in the realtime web world. Whether you know it or not, you&apos;ve probably benefitted from superfeedr&apos;s technology while using other services like gowalla, tumblr, etsy, posterous and many more.&lt;/p&gt;
&lt;p&gt;Together we&apos;ve manage to line up a ridiculously awesome list of speakers, that we&apos;re gradually announcing. So far, we&apos;ve announced &lt;a href=&quot;http://twitter.com/rauchg&quot;&gt;Guilleremo Rauch&lt;/a&gt; (creator of &lt;a href=&quot;http://socket.io&quot;&gt;socket.io&lt;/a&gt;), &lt;a href=&quot;http://twitter.com/leahculver&quot;&gt;Leah Culver&lt;/a&gt; (founder of &lt;a href=&quot;http://convore.com&quot;&gt;Convore&lt;/a&gt; and previously pownce.com), &lt;a href=&quot;http://twitter.com/substack&quot;&gt;James Halliday&lt;/a&gt; (JS hacker and creator of dnode, browserify, and a bunch of other awesome stuff under the alias &quot;substack&quot;). Also, we&apos;ve just added realtime veteran Jack Moffit (&lt;a href=&quot;http://twitter.com/metajack&quot;&gt;@metajack&lt;/a&gt;) and NowJS&apos;s Sridatta Thatipamala (&lt;a href=&quot;http://twitter.com/sridatta&quot;&gt;@sridatta&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Personally, I&apos;m way more excited about attending this event than I am being part of organizing it. These people are my heroes. We&apos;ve got several more really interesting folks on the TBA list as well.&lt;/p&gt;
&lt;p&gt;We&apos;ve been getting some great advice from &lt;a href=&quot;http://twitter.com/voodootikigod&quot;&gt;Chris Williams&lt;/a&gt; (&lt;a href=&quot;http://jsconf.com&quot;&gt;JSConf&lt;/a&gt;&apos;s daddy) on how to put on a kick-ass conference. We don&apos;t know if we&apos;ll make any money, in fact, our main goal is just to &lt;em&gt;not lose&lt;/em&gt; money. We just want to bring together all of these amazing people from various communities that are pushing the envelope of what can be done in a browser. We need to listen to each other, learn from each other and push each other to solve the problems that can make more awesome apps a possibility.&lt;/p&gt;
&lt;p&gt;In order for attendees to get the most value possible, we&apos;re going to do a presentation track (on the top floor) and then a hack-track (on the lower floor), where the presenters can do smaller, follow-up sessions, how-to&apos;s, training, etc. Multiple hack-tracks will be going on simultaneously. The goal being for people to be able to get more in-depth knowledge on the topics that interest them most.&lt;/p&gt;
&lt;p&gt;We&apos;re also trying hard to get representatives of various dev communities, so that no one stack is touted as the &quot;One True Way&quot;. That&apos;s just silly. We all have our favorites, I get that, but ultimately we&apos;re better off if we learn from each other, especially from those who are &lt;em&gt;not&lt;/em&gt; using our tools of choice. There&apos;s a whole batch of new problems to solve in building (and scaling) rich, real-time applications that work on as many devices as possible.&lt;/p&gt;
&lt;h2 id=&quot;the-details&quot;&gt;&lt;a href=&quot;#the-details&quot; aria-label=&quot;the details permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The details&lt;/h2&gt;
&lt;p&gt;KRTConf will be Nov. 7-8 in Portland, OR, all the details are on &lt;a href=&quot;http://krtconf.com&quot;&gt;krtconf.com&lt;/a&gt; and new stuff is being announced as it happens on twitter at &lt;a href=&quot;http://twitter.com/krtconf&quot;&gt;@krtconf&lt;/a&gt; and on this blog.&lt;/p&gt;
&lt;p&gt;If you wanna be there, you can get &lt;a href=&quot;http://krtconf.eventbrite.com/&quot;&gt;tickets on eventbrite&lt;/a&gt; and if you&apos;re interested in speaking, sponsoring or otherwise being involved in the event, email Adam &lt;a href=&quot;mailto:adam@krtconf.com&quot;&gt;adam@krtconf.com&lt;/a&gt; or myself &lt;a href=&quot;mailto:henrik@krtconf.com&quot;&gt;henrik@krtconf.com&lt;/a&gt; or hit us up on twitter &lt;a href=&quot;http://twitter.com/adambrault&quot;&gt;@adambrault&lt;/a&gt; &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@henrikjoreteg&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&apos;m super excited to be a part of this and hopefully I&apos;ll see you there!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Welcome, Melani]]></title><description><![CDATA[Monday will be Melani Brown's first day as a full-time &yet team member--we can't wait!Melani is a talented filmmaker and photographer who…]]></description><link>https://blog.andyet.com/2011/08/05/welcome-melani/</link><guid isPermaLink="false">https://blog.andyet.com/2011/08/05/welcome-melani/</guid><pubDate>Fri, 05 Aug 2011 16:50:21 GMT</pubDate><content:encoded>&lt;p&gt;Monday will be Melani Brown&apos;s first day as a full-time &amp;#x26;yet team member--we can&apos;t wait!&lt;/p&gt;
&lt;p&gt;Melani is a talented filmmaker and photographer who will be doing awesome stuff of that sort with us.&lt;/p&gt;
&lt;p&gt;She has worked on Kill Bill, Desperate Housewives, Nike commercials, and the online Old Spice social media ad campaign. She has photographed &lt;a href=&quot;http://www.flickr.com/photos/melanibrown/2850712230/in/set-72157594332254419&quot;&gt;Bon Iver&lt;/a&gt;, &lt;a href=&quot;http://www.flickr.com/photos/melanibrown/5440214362/in/photostream&quot;&gt;Sallie Ford &amp;#x26; the Sound Outside&lt;/a&gt;, and &lt;a href=&quot;http://www.flickr.com/photos/melanibrown/sets/72157594332254419/&quot;&gt;numerous indie bands&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a longtime friend of the equally talented &lt;a href=&quot;/team/amy/&quot;&gt;Amy Lynn Taylor&lt;/a&gt;, we were privileged to have Mel provide our team&apos;s photography a couple years ago. We&apos;ve enjoyed several one-off collaborations with her since, including inviting her to participate in our team&apos;s month-long stay in an Italian castle this Spring.&lt;/p&gt;
&lt;p&gt;It&apos;s been clear for some time that she&apos;s an unofficial member of our team, more than anything because she comfortably fits our approach and values: she&apos;s talented, creative, passionate, and has an attitude of encouraging those around her to grow and succeed.&lt;/p&gt;
&lt;p&gt;In her many years of travels across the globe, she could best be described as an itinerant blesser. We feel blessed to officially make her a part of our team.&lt;/p&gt;
&lt;p&gt;In addition to &lt;a href=&quot;http://andyet.net/blog/2011/jul/18/devcastle-the-movie/&quot;&gt;the great short film she made about our Italy adventure&lt;/a&gt;, here&apos;s a couple more examples of Mel&apos;s great work:&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/22474867?title=0&amp;byline=0&amp;portrait=0&quot; height=&quot;287&quot; frameborder=&quot;0&quot; width=&quot;510&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;http://vimeo.com/22474867&quot;&gt;coding &amp;#x26; designing from around the world&lt;/a&gt; from &lt;a href=&quot;http://vimeo.com/melanibrown&quot;&gt;Melani Brown&lt;/a&gt; on &lt;a href=&quot;http://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/19417828?title=0&amp;byline=0&amp;portrait=0&quot; height=&quot;287&quot; frameborder=&quot;0&quot; width=&quot;510&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;http://vimeo.com/19417828&quot;&gt;Pocket Portrait: 02 Ritchie Young&lt;/a&gt; from &lt;a href=&quot;http://vimeo.com/melanibrown&quot;&gt;Melani Brown&lt;/a&gt; on &lt;a href=&quot;http://vimeo.com&quot;&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Welcome, Shenoa]]></title><description><![CDATA[We are excited to add Shenoa Lawrence to the &yet team. She will be serving part-time as &yet's Community Coordinator, beginning last week…]]></description><link>https://blog.andyet.com/2011/08/01/welcome-shenoa/</link><guid isPermaLink="false">https://blog.andyet.com/2011/08/01/welcome-shenoa/</guid><pubDate>Mon, 01 Aug 2011 15:59:06 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d318b7ca013978836a6e078e952bb13d/7e076/shenoa-community-coordinator.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 54.3046357615894%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAQX/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/2gAMAwEAAhADEAAAAVZy2ZaSML//xAAbEAACAgMBAAAAAAAAAAAAAAABAgADERMxFP/aAAgBAQABBQL1vh7nsGwmDr8n/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHBAAAQMFAAAAAAAAAAAAAAAAAAECEBEhIjOB/9oACAEBAAY/ArUFy4bHQkf/xAAbEAEAAgIDAAAAAAAAAAAAAAABABEhQRCRwf/aAAgBAQABPyFfIEW2tSm7CZD5Kotm8RduDU//2gAMAwEAAgADAAAAELg//8QAGBEAAwEBAAAAAAAAAAAAAAAAAAFBESH/2gAIAQMBAT8QeOHFD//EABURAQEAAAAAAAAAAAAAAAAAAACB/9oACAECAQE/EFf/xAAdEAEAAgICAwAAAAAAAAAAAAABABEhMUFRYXHh/9oACAEBAAE/ECoiQUy0eiJBcxXxLxzMLIPRnUQAOAj5mxQNcQCan//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;Shenoa with some friends&quot;
        title=&quot;&quot;
        src=&quot;/static/d318b7ca013978836a6e078e952bb13d/3cb18/shenoa-community-coordinator.jpg&quot;
        srcset=&quot;/static/d318b7ca013978836a6e078e952bb13d/0a254/shenoa-community-coordinator.jpg 151w,
/static/d318b7ca013978836a6e078e952bb13d/c8fe0/shenoa-community-coordinator.jpg 303w,
/static/d318b7ca013978836a6e078e952bb13d/3cb18/shenoa-community-coordinator.jpg 605w,
/static/d318b7ca013978836a6e078e952bb13d/7e076/shenoa-community-coordinator.jpg 799w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We are excited to add &lt;a href=&quot;http://twitter.com/shenoalawrence&quot;&gt;Shenoa Lawrence&lt;/a&gt; to the &amp;#x26;yet team. She will be serving part-time as &amp;#x26;yet&apos;s Community Coordinator, beginning last week.&lt;/p&gt;
&lt;p&gt;Shenoa has taken a strong leadership role in our local tech community: &amp;#x3C;&lt;a href=&quot;http://meetup.com/doctype-society/&quot;&gt;!doctype society&gt;&lt;/a&gt;, &lt;a href=&quot;http://rm2think.com&quot;&gt;Room to Think&lt;/a&gt; (our local coworking movement), and &lt;a href=&quot;http://triconf.com&quot;&gt;TriConf&lt;/a&gt; (a local barcamp &amp;#x26;yet helped sponsor last weekend). She&apos;s also in the process of putting together &lt;a href=&quot;http://wecreatetc.com&quot;&gt;weCreate&lt;/a&gt;, a local directory of people, projects, and products that make up our community. Her dedication and contributions have been a major part of the continued success of all of the above.&lt;/p&gt;
&lt;p&gt;We want to affirm that dedication and empower her to continue it.&lt;/p&gt;
&lt;p&gt;Shenoa is a &lt;a href=&quot;http://shenoalawrence.com/&quot;&gt;veteran web developer and designer&lt;/a&gt;, and served as a leader of a community she was a part of in the San Francisco Bay Area. Members of our community have huge respect for Shenoa as an individual and as a contributor to the big success of our local dev community.&lt;/p&gt;
&lt;p&gt;Since its first days, &amp;#x26;yet has invested time and money in helping build our area&apos;s designer and developer community. Our team considers it one of the most important things we&apos;ve been privileged to contribute to.&lt;/p&gt;
&lt;p&gt;This is a continuation of those efforts.&lt;/p&gt;
&lt;p&gt;We take a realistic view that community is something that emerges from intentionally cultivated soil--there are both mechanic and organic aspects to a good community, and both require hard work.&lt;/p&gt;
&lt;p&gt;Since it began in February, &amp;#x3C;&lt;a href=&quot;http://meetup.com/doctype-society&quot;&gt;!doctype society&gt;&lt;/a&gt; has gained over 70 members and drawn participants from Walla Walla, Yakima, and Spokane--but we know there are many more who should be a part of our local web development, and creative community. And our aspirations for these groups are bigger than mere social gatherings--we want to spark the founding of numerous startups in our area and help provide resources for them to succeed.&lt;/p&gt;
&lt;p&gt;We&apos;re excited about what Shenoa has contributed so far to that end, thrilled to be able to team up with her further, and eagerly anticipate what&apos;s next.&lt;/p&gt;
&lt;p&gt;Please &lt;a href=&quot;http://twitter.com/shenoalawrence&quot;&gt;thank Shenoa&lt;/a&gt; for her hard work and dedication and for being willing to take on this new challenge as a continuity of what she&apos;s already helped to build.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Building a perpetual learning machine]]></title><description><![CDATA[In the midst of a particularly enjoyable college semester ten years ago, my good friend Eric Cadwell and I joked that a great job would be…]]></description><link>https://blog.andyet.com/2011/07/22/building-a-perpetual-learning-machine/</link><guid isPermaLink="false">https://blog.andyet.com/2011/07/22/building-a-perpetual-learning-machine/</guid><pubDate>Fri, 22 Jul 2011 12:26:15 GMT</pubDate><content:encoded>&lt;p&gt;In the midst of a particularly enjoyable college semester ten years ago, my good friend Eric Cadwell and I joked that a great job would be just going to school full-time for life.&lt;/p&gt;
&lt;p&gt;I decided to figure out how to make a career out of it, in one way or another.&lt;/p&gt;
&lt;p&gt;On the list of enjoyable things about the years that followed working as a pastor was the constant learning; I enjoy wrestling deeply with theology and its practicality, plus there’s no shortage of learning opportunities dealing with the human dynamics that come with ministry—painful, yes, but certainly plenty.&lt;/p&gt;
&lt;p&gt;When I started &amp;#x26;yet, I had the idea of building a business around the things that I had spent the bulk of my free-time learning (namely, web development and design). I figured if doing that could make me at least $30k a year, that was good enough. I mean, heck, there’s no school that’ll pay you a net gain of $30k to learn whatever you want!&lt;/p&gt;
&lt;p&gt;It&apos;s worked out better than I thought -- I&apos;ve improved my design skill and learned a ton about what it takes to make great software. Plus, you can&apos;t beat the opportunity to learn from people you&apos;ve helped teach.&lt;/p&gt;
&lt;p&gt;Amy hadn&apos;t designed for web when we added her to our team and now she&apos;s at the top of her class. Her design aesthetic has always been second-to-none, however, and I&apos;ve learned a huge amount from her intentional simplicity. Working with me has made me a much better designer and made me realize how far I have to go.&lt;/p&gt;
&lt;p&gt;We spent the first few months of James&apos;s time with us helping get him up to speed with our process and writing high quality HTML and CSS -- but more recently instead of teaching him, he&apos;s doing the educating on advanced CSS3 techniques.&lt;/p&gt;
&lt;p&gt;But we&apos;re just getting started.&lt;/p&gt;
&lt;p&gt;I feel like I&apos;ve only started with what our folks are capable of teaching -- and as we&apos;ve crossed the point of being a fun ad hoc group and into being a real company for some time now, our intent is to take advantage of some that stability to formalize our commitment to education.&lt;/p&gt;
&lt;p&gt;Thinking about all of this made us realize that if (1)you can build a business of diversely talented people who enjoy teaching and learning and (2) you intentionally make learning a formal part of your work, then essentially what you have is a miniature, ad-hoc university (in its most ideal form).&lt;/p&gt;
&lt;p&gt;And if that&apos;s what you have, why stop internally? Why not share it?&lt;/p&gt;
&lt;p&gt;So, today, we’re announcing &lt;a href=&quot;http://tumbleweed.it/&quot;&gt;Tumbleweed Tech&lt;/a&gt;, our effort to provide a solid alternative to the less-than-modern approach to web development taken at local colleges and universities.&lt;/p&gt;
&lt;p&gt;Don’t get me wrong. I love academics and degrees have their place, but sometimes, you just want to know what you need to know to dive in and get things done. Add to that access to some talented, experienced people, and we think it’s a great approach—one that many students will gain from.&lt;/p&gt;
&lt;p&gt;Tumbleweed Tech will begin this Fall.&lt;/p&gt;
&lt;p&gt;We have a list of potential classes outlined and we’ll be basing our initial offering based on what people want to learn. So &lt;a href=&quot;http://tumbleweed.it&quot;&gt;drop your name in if you’re interested&lt;/a&gt;! We’d love to have you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[/dev/castle The Movie]]></title><description><![CDATA[Our filmmaker friend Melani Brown made a cool short film about our month-long adventure working from a castle in Italy.In case you missed it…]]></description><link>https://blog.andyet.com/2011/07/18/devcastle-the-movie/</link><guid isPermaLink="false">https://blog.andyet.com/2011/07/18/devcastle-the-movie/</guid><pubDate>Mon, 18 Jul 2011 10:41:41 GMT</pubDate><content:encoded>&lt;p&gt;Our filmmaker friend &lt;a href=&quot;http://melanibrown.com/&quot;&gt;Melani Brown&lt;/a&gt; made a cool short film about our month-long adventure working from a castle in Italy.&lt;/p&gt;
&lt;iframe src=&quot;https://player.vimeo.com/video/26501892?title=0&amp;portrait=0&quot; height=&quot;287&quot; frameborder=&quot;0&quot; width=&quot;510&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;In case you missed it, here’s &lt;a href=&quot;http://andyet.net/blog/2011/mar/3/devcastle/&quot;&gt;the original blog post.&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[“Capable” isn’t a strategic planning metric]]></title><description><![CDATA[You have a dream.So, just like every single one of us, you ask, “Do I have what it takes?” The answer is yes. Every other answer is a lie…]]></description><link>https://blog.andyet.com/2011/07/15/capable-isnt-a-strategic-planning-metric/</link><guid isPermaLink="false">https://blog.andyet.com/2011/07/15/capable-isnt-a-strategic-planning-metric/</guid><pubDate>Fri, 15 Jul 2011 11:09:21 GMT</pubDate><content:encoded>&lt;p&gt;You have a dream.&lt;/p&gt;
&lt;p&gt;So, just like every single one of us, you ask, “Do I have what it takes?” &lt;/p&gt;
&lt;p&gt;The answer is yes. Every other answer is a lie, an excuse or a distraction. The call itself is enough of an answer. &lt;/p&gt;
&lt;p&gt;I consider myself good at a few things, passable at many, and passionate about more. What I’m capable of is completely irrelevant. I’m likely the worst to judge that anyway. &lt;/p&gt;
&lt;p&gt;You prove yourself “capable” by simply &lt;em&gt;doing&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;So do. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Choosing a template language(s)]]></title><description><![CDATA[Template languages: a densely populated land, where not even angels fear to tread.Let's rush right in.Mail merge for web developers.A…]]></description><link>https://blog.andyet.com/2011/07/13/choosing-a-template-languages/</link><guid isPermaLink="false">https://blog.andyet.com/2011/07/13/choosing-a-template-languages/</guid><pubDate>Wed, 13 Jul 2011 13:00:02 GMT</pubDate><content:encoded>&lt;p&gt;Template languages: a densely populated land, where not even angels fear to tread.&lt;/p&gt;
&lt;p&gt;Let&apos;s rush right in.&lt;/p&gt;
&lt;h3 id=&quot;mail-merge-for-web-developers&quot;&gt;&lt;a href=&quot;#mail-merge-for-web-developers&quot; aria-label=&quot;mail merge for web developers permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Mail merge for web developers.&lt;/h3&gt;
&lt;p&gt;A template language is mail merge for web developers.&lt;/p&gt;
&lt;p&gt;A template language is &lt;em&gt;not&lt;/em&gt; a &lt;a href=&quot;http://en.wikipedia.org/wiki/XSLT&quot;&gt;transformational grammar capable of specifying a projection between semantic signals and a diversely formatted symbolic representation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A template language is for taking crap and pooping it into HTML.&lt;/p&gt;
&lt;h3 id=&quot;pardon-my-french&quot;&gt;&lt;a href=&quot;#pardon-my-french&quot; aria-label=&quot;pardon my french permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;(Pardon my French)&lt;/h3&gt;
&lt;p&gt;Some template languages are programming languages.&lt;/p&gt;
&lt;p&gt;Every template language starts with the basic notion of inserting variable &lt;em&gt;data&lt;/em&gt; into a reusable &lt;em&gt;structure&lt;/em&gt;.
&lt;br&gt;
&lt;br&gt;
// C stdio - &lt;a href=&quot;http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html&quot;&gt;http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html&lt;/a&gt;
printf(&quot;There are %lu lights&quot;, num&lt;em&gt;lights);
&lt;br&gt;
&lt;br&gt;
# Python - &lt;a href=&quot;http://docs.python.org/library/stdtypes.html#string-formatting&quot;&gt;http://docs.python.org/library/stdtypes.html#string-formatting&lt;/a&gt;
data = {&apos;verb&apos;:&quot;run&quot;, &apos;subject&apos;:&quot;refrigerator&quot;,}
print &quot;See %(subject)s %(verb)s. %(verb)s, %(subject)s, %(verb)s!&quot; % data
&lt;br&gt;
&lt;br&gt;
// flatstache.js - &lt;a href=&quot;https://github.com/natevw/flatstache.js&quot;&gt;https://github.com/natevw/flatstache.js&lt;/a&gt;
var data = {thing:&quot;World&quot;};
Flatstache.to&lt;/em&gt;html(&quot;Hello, {{ thing }}!&quot;, data);&lt;/p&gt;
&lt;p&gt;But simple variable replacement isn&apos;t enough for most template languages.&lt;/p&gt;
&lt;p&gt;The three examples above are just &quot;string formatting&quot;, not &quot;template expansion&quot;: When &lt;code class=&quot;language-text&quot;&gt;num_lights&lt;/code&gt; is 1 we should say &quot;light&quot; instead. Maybe we&apos;d like to capitalize a string when we&apos;re using it at the beginning of a sentence. Maybe we want to style every other table row with alternating colors, or add a special border to the first and last list items...
&lt;br&gt;
&lt;br&gt;
&lt;table border=&apos;1&apos;&gt;
&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Age&lt;/th&gt;&lt;/tr&gt;
&amp;#x3C;?
$result = mysql&lt;em&gt;query(&quot;SELECT * FROM people&quot;);
while ($row = mysql&lt;/em&gt;fetch_array($result)) {
echo &quot;&lt;tr&gt;&lt;td&gt;&quot; . $row[&apos;Name&apos;] . &quot;&lt;/td&gt;&lt;td&gt;&quot; . $row[&apos;Age&apos;] . &quot;&lt;/td&gt;&lt;/tr&gt;&quot;;
}
?&gt;
&lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;Some template languages become PHP without the plumber&apos;s crack. When they&apos;re well-designed, these empower non-&quot;coders&quot; to dabble in programming logic without giving them to much rope to SQL inject themselves with.&lt;/p&gt;
&lt;h3 id=&quot;a-simpler-approach&quot;&gt;&lt;a href=&quot;#a-simpler-approach&quot; aria-label=&quot;a simpler approach permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;A simpler approach?&lt;/h3&gt;
&lt;p&gt;Other template languages are just template languages.&lt;/p&gt;
&lt;p&gt;These are &lt;a href=&quot;http://code.google.com/p/google-ctemplate/&quot;&gt;the&lt;/a&gt; &lt;a href=&quot;http://mustache.github.com/mustache.5.html&quot;&gt;ones&lt;/a&gt; &lt;a href=&quot;http://akdubya.github.com/dustjs/#guide&quot;&gt;that&lt;/a&gt; &lt;a href=&quot;http://json-template.googlecode.com/svn/trunk/doc/Introducing-JSON-Template.html&quot;&gt;talk&lt;/a&gt; a lot about separating &lt;em&gt;logic&lt;/em&gt; from &lt;em&gt;presentation&lt;/em&gt; in their documentation. What they mean is, they expect you&apos;ll be providing data to your templates via a perfectly good programming language. What they mean is, &quot;you shouldn&apos;t expect your template language to do a programming language&apos;s work&quot;.&lt;/p&gt;
&lt;p&gt;Usually these other template languages implement only two logic features: loops and conditionals. The only &quot;programming&quot; the template author can do is declare that certain sections of their template get repeated or left out if certain data has been repeated or left out.&lt;/p&gt;
&lt;h3 id=&quot;what-this-means&quot;&gt;&lt;a href=&quot;#what-this-means&quot; aria-label=&quot;what this means permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What this means&lt;/h3&gt;
&lt;p&gt;A template combines variable &lt;em&gt;data&lt;/em&gt; with a predefined &lt;em&gt;structure&lt;/em&gt;. Taking the programming out of the &lt;em&gt;structure&lt;/em&gt; means moving that programming to where the &lt;em&gt;data&lt;/em&gt; is gathered.&lt;/p&gt;
&lt;p&gt;Unfortunately, in situations where development roles are split between separate teams, this means that the &quot;Frontend&quot; team needs to rely more on the &quot;Backend&quot; team&apos;s help.&lt;/p&gt;
&lt;h3 id=&quot;what-else-this-means&quot;&gt;&lt;a href=&quot;#what-else-this-means&quot; aria-label=&quot;what else this means permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What else this means&lt;/h3&gt;
&lt;p&gt;Fortunately, this also means that the &quot;Frontend&quot; team needs to rely more on the &quot;Backend&quot; team&apos;s help. This might have some slight productivity drawbacks, but can lead to overall architectural and performance benefits.&lt;/p&gt;
&lt;p&gt;Maybe it&apos;s only because most programmers aren&apos;t people people, but careful &quot;separation of concerns&quot; typically pays dividends wherever it&apos;s applied to software. Fetching and manipulating data at a lower level forces everyone to think specifically about what information a given web page really needs, and how that might effect the simplicity or scalability of the system as a whole. (At last year&apos;s DjangoCon, we heard some interesting stories about &quot;little&quot; template changes causing an order-of-magnitude more database load.)&lt;/p&gt;
&lt;p&gt;Now there&apos;s nothing inherently evil about picking a more empowering template language — unless you&apos;re &quot;binding&quot; variables into your SQL queries using string concatenation, in which case Dante would like to interview you for &lt;a href=&quot;http://en.wikipedia.org/wiki/Inferno_(Dante)&quot;&gt;a book he&apos;s working on&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Better to give a good &quot;Frontend&quot; developer any programming features they need in their template language, than trust a bad &quot;Backend&quot; developer with all the power tools and blasting powder of a bona fide programming language.&lt;/p&gt;
&lt;h3 id=&quot;what-to-do-about-it&quot;&gt;&lt;a href=&quot;#what-to-do-about-it&quot; aria-label=&quot;what to do about it permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;What to do about it&lt;/h3&gt;
&lt;p&gt;It should be clear why there are so very very many different &quot;competing&quot; template engines: every one makes different choices about &lt;em&gt;how&lt;/em&gt; a template is defined, and also about &lt;em&gt;what&lt;/em&gt; a template &lt;em&gt;can&lt;/em&gt; define!&lt;/p&gt;
&lt;p&gt;So what should we look for in a template language?&lt;/p&gt;
&lt;p&gt;The &quot;perfect blend&quot; will vary from team to team, and even from project to project. But overall, a template language should:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Be easy to implement in and access from the languages that matter these days — For &amp;#x26;yet right now that means JavaScript, Python and (in a pinch) Objective-C. Your thing might be Ruby and C#, that&apos;s cool too. The obvious point is that if a templating engine would be hard for you to use, it&apos;s the wrong one for you to choose. On the flip side: if your Django/Rails/Express/jQuery/framework-thing makes it easy to use one particular built-in template language, that&apos;s the one for you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Encourage thoughtful use of source data — A template language shouldn&apos;t tie the hands of its primary users, but it does need to prevent as much fat-fingering as possible. Mistakes like &lt;a href=&quot;http://en.wikipedia.org/wiki/Cross-site_scripting&quot;&gt;Cross-Site Scripting&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/SQL_injection&quot;&gt;SQL injection&lt;/a&gt; are unacceptable for most projects. On a few projects, unoptimized database usage could be costly. On all projects, keeping everyone aware of what data is available (and how) is beneficial.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keep the app as a whole clean and simple — Boring boilerplate code encourages abundant annoying bugs. Any stuff that doesn&apos;t make your function, your page or your project special all needs to be typed correctly anyway. So take the &quot;template language&quot; idea of variable data vs. reusable structure, and apply that to your team&apos;s work as a whole. Your template language, like any language, should help you simply say what you mean.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At &amp;#x26;&lt;a href=&quot;http://andyet.net&quot;&gt;yet&lt;/a&gt; we&apos;ve used everything from &lt;a href=&quot;https://docs.djangoproject.com/en/dev/ref/templates/api/&quot;&gt;Django&apos;s template system&lt;/a&gt; (a full-featured engine that mimics Python to good effect) to &lt;a href=&quot;https://github.com/janl/mustache.js&quot;&gt;mustache.js&lt;/a&gt; (an intentionally simple language with compatible libraries in many programming languages), and other interesting ones like &lt;a href=&quot;http://jade-lang.com/&quot;&gt;Jade&lt;/a&gt; and &lt;a href=&quot;http://haml-lang.com/&quot;&gt;Haml&lt;/a&gt; (which compile indented structures into HTML). In the future we may find something like &lt;a href=&quot;http://knockoutjs.com/&quot;&gt;Knockout&lt;/a&gt; useful. In past lives we&apos;ve been known to use XSLT and various PHP and ColdFusion solutions to get the job done.&lt;/p&gt;
&lt;p&gt;Remember that in the end, your choice of template language is tiny and insignificant compared to, say, your choice of the people you work for and the people you work with. Each templating engine will have its upsides and downsides; being conscious of its overall approach, goals and shortcomings will help you and your team use it most effectively.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Fitt's Law in meatspace]]></title><description><![CDATA[At &yet, we're always fighting to get ourselves to log hours. We recently came up with a method inspired by Fitt's Law that's proven quite…]]></description><link>https://blog.andyet.com/2011/07/12/fitts-law-in-meatspace/</link><guid isPermaLink="false">https://blog.andyet.com/2011/07/12/fitts-law-in-meatspace/</guid><pubDate>Tue, 12 Jul 2011 11:34:12 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/062beec7e0bf59fabc5673d0da4feef2/41099/banned-debanned_.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 500px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 74.8344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABAABBf/EABUBAQEAAAAAAAAAAAAAAAAAAAED/9oADAMBAAIQAxAAAAETwvm8WyX/xAAaEAADAQADAAAAAAAAAAAAAAABAgMRAAQS/9oACAEBAAEFAoS0mI40yD164Wuvkud//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFREBAQAAAAAAAAAAAAAAAAAAACH/2gAIAQIBAT8Bqv/EABcQAQADAAAAAAAAAAAAAAAAABAAITH/2gAIAQEABj8Cbmn/xAAZEAADAQEBAAAAAAAAAAAAAAAAAREhMVH/2gAIAQEAAT8h0GLLhAwVvyFyang50f/aAAwDAQACAAMAAAAQ19//xAAXEQADAQAAAAAAAAAAAAAAAAAAASEx/9oACAEDAQE/EHsIf//EABcRAAMBAAAAAAAAAAAAAAAAAAABIWH/2gAIAQIBAT8QexQf/8QAHBABAAMAAgMAAAAAAAAAAAAAAQARITFBUWFx/9oACAEBAAE/EGccSuPceUB6ipcIiwGMvuJFLKtePkUKp//Z&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;banned - debanned&quot;
        title=&quot;&quot;
        src=&quot;/static/062beec7e0bf59fabc5673d0da4feef2/41099/banned-debanned_.jpg&quot;
        srcset=&quot;/static/062beec7e0bf59fabc5673d0da4feef2/0a254/banned-debanned_.jpg 151w,
/static/062beec7e0bf59fabc5673d0da4feef2/c8fe0/banned-debanned_.jpg 303w,
/static/062beec7e0bf59fabc5673d0da4feef2/41099/banned-debanned_.jpg 500w&quot;
        sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At &amp;#x26;yet, we&apos;re always fighting to get ourselves to log hours. We recently came up with a method inspired by Fitt&apos;s Law that&apos;s proven quite effective.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Fitts&amp;#x27;s_law&quot;&gt;Fitt&apos;s Law&lt;/a&gt;, as it applies to interface design, essentially says the smaller and further away a target is, the harder it is to hit.&lt;/p&gt;
&lt;p&gt;That&apos;s why we get Apple positioning the OS X menu at the very top of our workspace and the Dock at the bottom. The edge of the screen can be said to have infinite width in the direction the mouse hits it, making it an easy target.&lt;/p&gt;
&lt;p&gt;What we&apos;ve realized is that Fitt&apos;s Law can apply in physical space, too. Take time tracking, for example.&lt;/p&gt;
&lt;p&gt;We all want to track our time, but nothing we&apos;ve tried has worked. Lots of methods and tools help &lt;em&gt;some&lt;/em&gt; people, but there are few things that help &lt;em&gt;everyone&lt;/em&gt;. Nagging and reminders are worthlessly ineffective when it comes to changing behavior. Tools are hit or miss.&lt;/p&gt;
&lt;p&gt;We&apos;ve tried lots of things, but this one was 100% successful: over several weeks&apos; time, the longest any person went without logging their hours was a day and a half—and most logged them daily. That has never happened in three years of trying to solve this.&lt;/p&gt;
&lt;p&gt;Here&apos;s how we &quot;Fittsed&quot; time-tracking.&lt;/p&gt;
&lt;p&gt;Logging time effectively is a very hard thing. Doing it consistently means a whole lot of tiny actions and a ton of reminders, each individual piece fairly meaningless. To further complicate matters, it&apos;s something that highly productive people naturally want to &quot;background&quot;, not stick in their face while getting stuff done. That means &lt;em&gt;by design&lt;/em&gt;, it&apos;s going to be easy to forget.&lt;/p&gt;
&lt;p&gt;What if we could associate logging time with the &quot;edge&quot; of our workspace in real life, not the workspace itself?&lt;/p&gt;
&lt;p&gt;Our kitchen is central to our office in almost every way. We keep it stocked daily with whatever snacks and drinks each member of our team wants to have available. The coffee&apos;s there and lots of great conversations get started in the kitchen, too. Everyone uses it every day, all day—typically at stopping points in their work.&lt;/p&gt;
&lt;p&gt;I know from experience it won&apos;t work to just stick a reminder on my monitor or where I&apos;ll see it as I walk away from my desk. Unlike those, the kitchen is a destination. It&apos;s a hard &quot;edge&quot; in the office interface.&lt;/p&gt;
&lt;p&gt;So now we use it as a privilege, not a right. There is a piece of paper taped to the door with a line down the middle and everyone&apos;s names on tiny Post-It Notes. On one side is the word &quot;BANNED&quot; and on the other, &quot;DEBANNED&quot;.&lt;/p&gt;
&lt;p&gt;If I haven&apos;t logged my hours within the past 24 hours, my name gets moved from the &quot;DEBANNED&quot; to the &quot;BANNED&quot; list (by Lisa, our office manager). All I have to do to get it moved back is go to my office and spend a moment logging hours.&lt;/p&gt;
&lt;p&gt;The centrality of the kitchen means it&apos;s easily enforced by peer pressure and the additional office fun of public &quot;shaming&quot;.&lt;/p&gt;
&lt;p&gt;It&apos;s helped along by another edge: the hallway and the kitchen are also the edge of my personal bubble. When we&apos;re out in the hall, we rib each other and tease each other and push each other to succeed on whatever we&apos;re working on together. That edge reminds me not just of the edge of my workspace, but the edge of where &quot;I&quot; end and &quot;we&quot; begin. Not a bad place to be reminded of the intrinsic value of logging hours.&lt;/p&gt;
&lt;p&gt;It&apos;s surprised us how well this has worked. In fact, un-banned people walking into the kitchen mid-day have gone back to log their recent hours because of the physical space reminder.&lt;/p&gt;
&lt;p&gt;For some time, we have been thinking constantly about ways to improve the user experience of accomplishing big things as a team with minimal intrusion and maximum benefit. Most of the learning we&apos;ve done in this area we&apos;ve been pouring into a product we&apos;ve been building called &lt;a href=&quot;http://andbang.com&quot;&gt;&amp;#x26;!&lt;/a&gt; (&quot;and bang&quot;). You can &lt;a href=&quot;http://andbang.com&quot;&gt;get on the invite list here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;-- &lt;/p&gt;
&lt;p&gt;Many thanks to &lt;a href=&quot;http://twitter.com/natevw&quot;&gt;Nate&lt;/a&gt; for his critical feedback on this post, without which it might have been even more abstract and made less sense. :) But, hey, you know what &lt;a href=&quot;https://twitter.com/#!/natevw/status/26491138945&quot;&gt;they say...&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Using CSS3 to create an image-free progress bar]]></title><description><![CDATA[I've been playing a lot with advanced pseudo-classes and pseudo-elements for a project Aaron and I have been working on.Originally, I was…]]></description><link>https://blog.andyet.com/2011/07/11/using-css3-to-create-an-image-free-progress-bar/</link><guid isPermaLink="false">https://blog.andyet.com/2011/07/11/using-css3-to-create-an-image-free-progress-bar/</guid><pubDate>Mon, 11 Jul 2011 16:42:01 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve been playing a lot with advanced pseudo-classes and pseudo-elements for a project Aaron and I have been working on.&lt;/p&gt;
&lt;p&gt;Originally, I was just going to share it as a blog post, but instead, Aaron and I hacked together as &lt;a href=&quot;http://whereamiat.com/&quot;&gt;a generator you can use to make a purely CSS3 progress bar&lt;/a&gt;, like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/progress-bar.png&quot; alt=&quot;progress bar&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here&apos;s &lt;a href=&quot;http://whereamiat.com/how.html&quot;&gt;how we did it&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[An Introduction to Thoonk!]]></title><description><![CDATA[As application developers, we persist data in tables which are constantly updated, leaving most of the application’s components and user…]]></description><link>https://blog.andyet.com/2011/06/21/an-introduction-to-thoonk/</link><guid isPermaLink="false">https://blog.andyet.com/2011/06/21/an-introduction-to-thoonk/</guid><pubDate>Tue, 21 Jun 2011 02:00:07 GMT</pubDate><content:encoded>&lt;p&gt;As application developers, we persist data in tables which are constantly updated, leaving most of the application’s components and user-interface in the dark until it asks for the data.&lt;/p&gt;
&lt;p&gt;[Movie trailer voice] Imagine a world where these tables push change-events to any piece of your application stack, in diverse languages and on multiple servers.[/Movie trailer voice]&lt;/p&gt;
&lt;p&gt;Enter Thoonk.&lt;/p&gt;
&lt;p&gt;Clustering Node.js instances, communicating between service components in different languages and on different machines, forking off asynchronous jobs for reliability and queuing of work, communicating between APIs and views, and sending events to real-time webapps are all problems that can be solved with messaging.&lt;/p&gt;
&lt;p&gt;Thoonk solves these problems more gracefully than simple messaging because the messages are change-events on persisted data.&lt;/p&gt;
&lt;p&gt;Thoonk is a Redis schema for manipulating advanced, live objects (feeds, sorted-feeds, queues, and job-queues, etc). Thoonk is also a couple of implementations of this schema (currently &lt;a href=&quot;https://github.com/andyet/thoonk.js&quot;&gt;thoonk.js&lt;/a&gt; for Node.js and &lt;a href=&quot;https://github.com/andyet/thoonk.py&quot;&gt;thook.py&lt;/a&gt; for Python).&lt;/p&gt;
&lt;p&gt;Thoonk is a lot of things, which I will describe, but really what I would like you to get out of this is what the concept is useful for.&lt;/p&gt;
&lt;p&gt;A feed is a list of data entries that have publish, edit, retract, and other events associated with those entries. A feed brings to mind ATOM or RSS to most people, but I think feeds are more useful when the associated events are broadcast on publish-subscribe channels so that data can be synchronized. Redis contains both of the necessary components (object storage and publish-subscribe channels).&lt;/p&gt;
&lt;p&gt;Thoonk feeds enable our “live tables” fantasy.&lt;/p&gt;
&lt;h3 id=&quot;lets-get-specific-about-thoonk-feed-types&quot;&gt;&lt;a href=&quot;#lets-get-specific-about-thoonk-feed-types&quot; aria-label=&quot;lets get specific about thoonk feed types permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Let’s get specific about Thoonk feed-types.&lt;/h3&gt;
&lt;p&gt;Please refer to the &lt;a href=&quot;https://github.com/andyet/thoonk.js&quot;&gt;Thoonk.js&lt;/a&gt; and &lt;a href=&quot;https://github.com/andyet/thoonk.py&quot;&gt;Thoonk.py&lt;/a&gt; documentation for examples.&lt;/p&gt;
&lt;p&gt;The basic feed is a list of items sorted by publish time. Verbs on these objects include publish, edit, and retract. Feeds may be configured to have a max-number of items, which when exceeded, drops the oldest items. Every item may have a unique assigned id, or Thoonk will generate one for you.&lt;/p&gt;
&lt;p&gt;Sorted-Feeds are similar to feeds, but they have no item limit (beyond practical memory limitations) and are sorted by publishing items relative to existing item ids. Verbs for sorted-feeds include append, prepend, publishBefore, publishAfter, move, edit, and retract. Sorted-feeds emit position updates when an item is published or moved in addition to publish, edit, and retract events.&lt;/p&gt;
&lt;p&gt;Queues contain items that can be placed at the beginning or end, producing FIFO and LIFO queues. A queue get is a blocking operation with an optional timeout that pops an item off of the end. Queues can be used for simple messaging and task distribution.&lt;/p&gt;
&lt;p&gt;Job channels distribute items in a guaranteed completion manner. Jobs consist of three queues: available jobs, in-flight jobs, and stalled job. Like queues, jobs can be pushed to the beginning or end of available jobs and getting a job is a blocking operation with a timeout. Job verbs include: publish, retract, get, cancel (place an in-flight job back into available-jobs), stall (place a job out of the way that has been a problem), retry (place a stalled job as available).&lt;/p&gt;
&lt;p&gt;Sets will be added in the near future as a means for maintaining live filters/queuries for feeds and other data.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://5px.it/thoonk/images/thoonk-illustration.jpg&quot; alt=&quot;thoonk illustration&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;an-example-thoonk-ecosystem&quot;&gt;&lt;a href=&quot;#an-example-thoonk-ecosystem&quot; aria-label=&quot;an example thoonk ecosystem permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;An example Thoonk ecosystem:&lt;/h3&gt;
&lt;p&gt;Thoonk is a tool which allows you create an Internet service as a wide ecosystem rather than a deep application. Say we provide a series of 8 node.js processes to take advantage of the number of CPU threads available. This node.js application provides a websocket interface to a browser-js application with live events coming from Thoonk feeds on Redis, organized by individual users and teams. In another process, we might run a Ruby service that provides a REST interface for manipulating and querying objects within users and groups. Say also that we want to peer certain data with other services -- we can run a Python process which provides XMPP Publish-Subscribe (XEP-0060) and a Java interface which provides a PubsubHubbub interface. In addition to that, background jobs that absolutely have to be done can be pushed through a job system with workers running in C.&lt;/p&gt;
&lt;p&gt;All of these separate components subscribe to the feeds pertinent to their function as well as provide relevant ACL and interface to the end-points. You are now free to use the most appropriate tools for the job, distribute load, organize application data, and selectively synchronize state easily. Of course, if you don’t have to have a lot of processes on a lot of servers in a lot of languages, you can still take advantage of compartmentalizing and duplicating your componets.&lt;/p&gt;
&lt;h3 id=&quot;backstory&quot;&gt;&lt;a href=&quot;#backstory&quot; aria-label=&quot;backstory permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Backstory&lt;/h3&gt;
&lt;p&gt;I find Messaging to be an interesting problem, particularly when machines communicate to share state, make requests, etc. However, messaging has limited use without persistent data, which is why I like XMPP Publish-Subscribe (XEP-0060) so much. Feeds of data -- combining data-persistence with publish-subscribe events about changes to the data, is incredibly valuable in machine-to-machine communication.&lt;/p&gt;
&lt;p&gt;This is something that I’ve been applying to clustering, configuration distribution, job distribution and management, and real-time webapps, and other problems for years now in my consulting work.&lt;/p&gt;
&lt;p&gt;Then, I discovered Redis, which is a very fast key-store-with-containers database that also includes publish-subscribe, and I immediately knew what I had to build.&lt;/p&gt;
&lt;p&gt;I’m publishing this as MIT because I not only want to share it, but I want your feedback, harsh criticism, and contributions. We need more implementations in other languages, and I’d love to see people publish tools that contribute to Thoonk interfaces. In addition, please point out flaws in the contract.txt (schema) document, show us your extensions and own object types, etc.&lt;/p&gt;
&lt;p&gt;Just hit up myself &lt;a href=&quot;http://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; and/or Lance Stout &lt;a href=&quot;http://twitter.com/lancestout&quot;&gt;@lancestout&lt;/a&gt; on twitter, follow the github projects (&lt;a href=&quot;https://github.com/andyet/thoonk.js&quot;&gt;Thoonk.js&lt;/a&gt; and &lt;a href=&quot;https://github.com/andyet/thoonk.py&quot;&gt;Thoonk.py&lt;/a&gt;), and watch &lt;a href=&quot;http://thoonk.com/&quot;&gt;http://thoonk.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Our team at &amp;#x26;yet always seems to find our way to work on interesting things, so be sure to &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;follow us on Twitter&lt;/a&gt; for the latest.&lt;/p&gt;
&lt;p&gt;-Nathan Fritz, &amp;#x26;yet Chief Architect&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Using the REST interface as the JavaScript interface with Fermata]]></title><description><![CDATA[In support of an upcoming &yet product (ssssssh!), I was asked to create a JavaScript wrapper around a REST-based API we're using from node…]]></description><link>https://blog.andyet.com/2011/05/09/using-the-rest-interface-as-the-javascript-interfa/</link><guid isPermaLink="false">https://blog.andyet.com/2011/05/09/using-the-rest-interface-as-the-javascript-interfa/</guid><pubDate>Mon, 09 May 2011 12:11:09 GMT</pubDate><content:encoded>&lt;p&gt;In support of an upcoming &amp;#x26;yet product (&lt;a href=&quot;http://andbang.com/&quot;&gt;ssssssh!&lt;/a&gt;), I was asked to create a JavaScript wrapper around a REST-based API we&apos;re using from &lt;a href=&quot;http://nodejs.org/&quot;&gt;node.js&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&apos;ve been there, you might know how it goes: guess which API features the current project actually needs, make up some sort of &quot;native&quot; object representation, implement some bridge code that kinda works, and as a finishing touch, slap a link to the service&apos;s &lt;em&gt;real&lt;/em&gt; documentation atop the code you left stubbed out for later.&lt;/p&gt;
&lt;p&gt;Or, you find &lt;em&gt;someone else&apos;s&lt;/em&gt; wrapper library. They took the time to implement most features, and even wrote their own version of the documentation — but the project &lt;em&gt;they&lt;/em&gt; needed it for was cancelled years ago, so their native library still wraps the previous version of the server API, without the new features you need.&lt;/p&gt;
&lt;h4 id=&quot;facts&quot;&gt;&lt;a href=&quot;#facts&quot; aria-label=&quot;facts permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;FACTS&lt;/h4&gt;
&lt;p&gt;On one hand, the HTTP REST server offers all the newest features, with official usage documented by the service provider. On the other hand, your JavaScript code should be fluently written, following the native programming language idioms. Can we keep it that way?&lt;/p&gt;
&lt;p&gt;It&apos;s a paradox, really:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the REST interface is the BEST interface.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the best interface is a native interface.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do you see where this is going? It took me a while, but after wrestling with the design of yet another web service wrapper, I finally saw the whole coin that I&apos;d been flipping. It&apos;s called &lt;a href=&quot;https://github.com/andyet/fermata&quot;&gt;Fermata&lt;/a&gt;, because when I finally put the two sides together I was &lt;a href=&quot;http://andyet.net/blog/2011/mar/3/devcastle/&quot;&gt;working from a cheerful Italian caffè&lt;/a&gt; and needed a lively but REST-ful word.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;http://en.wikipedia.org/wiki/Representational_State_Transfer&quot;&gt;REST&lt;/a&gt; you have nouns and verbs — resources and methods — URLs and GET/PUT/POSTs. In JavaScript you have objects and methods — nouns and verbs. So in Fermata, URLs are objects, and methods are, well...methods on those objects:
&lt;br&gt;
&lt;br&gt;
var rest&lt;em&gt;server = fermata.api({url:&quot;&lt;a href=&quot;http://couchdb.example.com:5984%22%7D&quot;&gt;http://couchdb.example.com:5984&quot;}&lt;/a&gt;);
var my&lt;/em&gt;document = rest&lt;em&gt;server.mydata.sample&lt;/em&gt;doc;
my_document.put({title:&quot;Fermata blog post&quot;, content:&quot;?&quot;}, function (err, response) { if (!err) console.log(&quot;Relax, your data is in good hands.&quot;); });
&lt;/p&gt;
&lt;p&gt;Hey, presto, abracadabra! Pretty simple, eh?&lt;/p&gt;
&lt;h4 id=&quot;sois-it-magic&quot;&gt;&lt;a href=&quot;#sois-it-magic&quot; aria-label=&quot;sois it magic permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So...is it magic?&lt;/h4&gt;
&lt;p&gt;Yes, it is magic.&lt;/p&gt;
&lt;h4 id=&quot;explain-this-sleightly-hand-or-die&quot;&gt;&lt;a href=&quot;#explain-this-sleightly-hand-or-die&quot; aria-label=&quot;explain this sleightly hand or die permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Explain this sleightly hand. Or die.&lt;/h4&gt;
&lt;p&gt;Easy there, fair Internet reader person! Your dollar was just hiding right there in your ear.&lt;/p&gt;
&lt;p&gt;To make the dot syntax work without having to know all the paths available on the server, Fermata uses a feature of an upcoming JavaScript Harmony proposal called &lt;a href=&quot;http://wiki.ecmascript.org/doku.php?id=harmony:proxies&quot;&gt;catch-all proxies&lt;/a&gt;. Proxy-fied objects finally give JavaScript developers a way to intercept all access to an object or function, injecting custom behaviour that would otherwise be impossible.&lt;/p&gt;
&lt;p&gt;ECMAScript 5 (the latest JavaScript standard; you can tell it is &lt;em&gt;Web Standard&lt;/em&gt; since it ends in 5) let us &lt;a href=&quot;https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty&quot;&gt;define property descriptors&lt;/a&gt; to handle the actual fetching and storing of pre-declared object keys — that is, you could have custom behaviour for specific properties only if their names were known beforehand:
&lt;br&gt;
&lt;br&gt;
var myObject = {}
Object.defineProperty(myObject, &apos;someSpecificProperty&apos;, {get: function () { return &quot;someSpecificProperty has this value&quot;; }});
myObject.someSpecificProperty === &quot;someSpecificProperty has this value&quot;;
myObject.someOtherProperty === undefined;
&lt;/p&gt;
&lt;p&gt;ECMAScript Harmony (an in-progress proposal for the next version of JavaScript) wants to take this a step further: rather than just controlling a few pre-defined properties of an object, you can &lt;a href=&quot;https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Proxy&quot;&gt;control access to &lt;em&gt;any&lt;/em&gt; key&lt;/a&gt; — the property&apos;s keyname is handed to a completely generic &quot;get&quot; function trap on the object:
&lt;br&gt;
&lt;br&gt;
var myObject = Proxy.create({get: function (obj, keyName) { return keyName + &quot; has this value&quot;; }}, {});
myObject.someSpecificProperty === &quot;someSpecificProperty has this value&quot;;
myObject.someOtherProperty === &quot;someOtherProperty has this value&quot;;
&lt;/p&gt;
&lt;p&gt;So the subpath keys of a Fermata URL don&apos;t actually exist. (I &lt;em&gt;told&lt;/em&gt; you it was magic.) Instead, when you assign &lt;code class=&quot;language-text&quot;&gt;var obj = url.path&lt;/code&gt; the JavaScript engine calls a proxy &quot;trap&quot; handler function, that Fermata provides, instead: &quot;hey, for key named &lt;code class=&quot;language-text&quot;&gt;path&lt;/code&gt; on the object &lt;code class=&quot;language-text&quot;&gt;url&lt;/code&gt;, what should I say the value is?&quot;. Fermata says: &quot;I&apos;ll make a new, slightly longer, URL proxy&quot; and so that&apos;s what the JavaScript engine assigns to &lt;code class=&quot;language-text&quot;&gt;var obj&lt;/code&gt;. If you then access a property on &lt;code class=&quot;language-text&quot;&gt;obj&lt;/code&gt;, Fermata just returns yet another object created via Proxy. Smoke and mirrors.&lt;/p&gt;
&lt;p&gt;Of course, where there&apos;s smoke and mirrors there must be fire and medicine cabinets. I said ECMAScript Harmony is a proposal that &quot;wants to&quot; standardize Proxy objects in JavaScript — a future version of JavaScript. Fortunately for us impatient types, an intrepid developer named &lt;a href=&quot;http://blog.samshull.com/&quot;&gt;Sam Shull&lt;/a&gt; has stocked the node.js medicine cabinet with &lt;a href=&quot;https://github.com/samshull/node-proxy&quot;&gt;node-proxy&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;While it differs a little from the official Harmony proposal, his V8 Proxy library made Fermata possible. Made Fermata magic.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;dramatic pause&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;but-my-web-browser-isnt-magic-yet&quot;&gt;&lt;a href=&quot;#but-my-web-browser-isnt-magic-yet&quot; aria-label=&quot;but my web browser isnt magic yet permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;But my web browser isn&apos;t magic, yet&lt;/h4&gt;
&lt;p&gt;Firefox 4&apos;s JavaScript engine implements the new Proxy object feature, but to reliably use Fermata&apos;s magic on the web we&apos;d have to wait for broader support. (Chrome &lt;a href=&quot;http://peter.sh/2011/04/spring-loaded-tabs-improved-border-rendering-and-the-web-request-api/&quot;&gt;might be next&lt;/a&gt;; the race is on, fellas!) In the meantime, I&apos;ve designed Fermata so that anything you can do with dots and brackets you can do with parentheses, and more!
&lt;br&gt;
&lt;br&gt;
var homebase = fermata.api({url:&quot;&quot;, user:&quot;webapp&quot;, password:SESSION_ID});
var latestMessages = homebase(&apos;api&apos;)(&apos;user&apos;)(&apos;messages.json&apos;);
latestMessages() === &quot;/api/user/messages.json&quot;;    // use empty parens for the URL as a string
latestMessages.get(function (e, messages) { console.log(messages); });
&lt;/p&gt;
&lt;p&gt;You can also use the parenthesis syntax to pass an array, which is how you prevent the automatic URL component escaping Fermata does normally. Starting from the &lt;a href=&quot;http://couchdb.apache.org/&quot;&gt;CouchDB&lt;/a&gt; restServer example above:
&lt;br&gt;
&lt;br&gt;
recent&lt;em&gt;docs = rest&lt;/em&gt;server(&apos;mydata&apos;)([&apos;&lt;em&gt;design/app/&lt;/em&gt;view/by_date&apos;], {reduce:false, descending:true, limit:10});  // keep a view query handy
recent&lt;em&gt;docs() === &quot;&lt;a href=&quot;http://couchdb.example.com:5984/mydata/&quot;&gt;http://couchdb.example.com:5984/mydata/&lt;/a&gt;&lt;/em&gt;design/app/&lt;em&gt;view/by&lt;/em&gt;date?reduce=false&amp;#x26;descending=true&amp;#x26;limit=10&quot;;
recent_docs.get(...you know the drill...);
&lt;/p&gt;
&lt;h4 id=&quot;volunteer-from-the-audience&quot;&gt;&lt;a href=&quot;#volunteer-from-the-audience&quot; aria-label=&quot;volunteer from the audience permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Volunteer from the audience&lt;/h4&gt;
&lt;p&gt;I&apos;d encourage you to give &lt;a href=&quot;https://github.com/andyet/fermata&quot;&gt;Fermata&lt;/a&gt; a spin the next time you only want &lt;em&gt;magic&lt;/em&gt; cutting between you and your favorite REST service. It&apos;s &lt;a href=&quot;https://github.com/andyet/fermata&quot;&gt;hosted on github&lt;/a&gt; and &lt;a href=&quot;http://search.npmjs.org/#/fermata&quot;&gt;installable via npm&lt;/a&gt;, under the terms of your friendly local MIT License.&lt;/p&gt;
&lt;p&gt;After writing and using various REST wrapper interfaces through the years, I&apos;m excited that I can finally speak both fluent HTTP and native JavaScript at the same time. In the office next door, &lt;a href=&quot;http://andyet.net/team/henrik/&quot;&gt;Henrik&lt;/a&gt; is already using it from node.js to access several REST service APIs via the one consistent interface Fermata provides. As web applications move more code to the client, and more services implement careful &lt;a href=&quot;http://en.wikipedia.org/wiki/Cross-Origin_Resource_Sharing&quot;&gt;CORS&lt;/a&gt; support, &lt;/p&gt;
&lt;p&gt;Fermata can provide a high-level AJAX microframework in the browser too.&lt;/p&gt;
&lt;p&gt;One next step for Fermata is to add plug-in support for taking care things like of default URLs, setting required headers, converting from XML instead of JSON, and signing OAuth access. The idea is not to wrap the wrapper. More like a musical key signature: do some initial site-specific setup, and the plugin will take care of any API-specific themes while the &lt;em&gt;rest&lt;/em&gt; of your JavaScript notation is consistent. Something along the lines of:
&lt;br&gt;
&lt;br&gt;
var twitter&lt;em&gt;client = fermata.api({twitter:CLIENT&lt;/em&gt;KEY, user:ID, solemn&lt;em&gt;developer&lt;/em&gt;promise:&quot;I accept and do acknowledge Tweetie&apos;s forever victory, it was a fantastic app while earning its overlord status.&quot;});
twitter&lt;em&gt;client.statuses.user&lt;/em&gt;timeline.get(...);    // same ol&apos; Fermata, but plugin is handling OAuth and format stuff
&lt;/p&gt;
&lt;p&gt;...maybe? Feedback on the plug-in interface, and anything really, is always appreciated!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[/dev/castle]]></title><description><![CDATA[The Four-Hour Workweek irked me before I decided to read it and blew my mind once I chose to.Not only that, I blame that book for the fact…]]></description><link>https://blog.andyet.com/2011/03/03/devcastle/</link><guid isPermaLink="false">https://blog.andyet.com/2011/03/03/devcastle/</guid><pubDate>Thu, 03 Mar 2011 11:08:57 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d91a86c7ffbfe2b53f3d9b39969b9ea1/d4b53/frickingcastle.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 150.3311258278146%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAeABQDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAECAwQF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgMA/9oADAMBAAIQAxAAAAHwN56A4ECg8Wp2SZf/xAAaEAADAQADAAAAAAAAAAAAAAABEBECAAMh/9oACAEBAAEFAudeasAFiDPloVX/xAAZEQACAwEAAAAAAAAAAAAAAAAAEQECEEH/2gAIAQMBAT8BrHcYz//EABkRAAIDAQAAAAAAAAAAAAAAAAARAQIQQf/aAAgBAgEBPwG08xCP/8QAHRAAAgIBBQAAAAAAAAAAAAAAAREAAhASICExQf/aAAgBAQAGPwKaj0MFuV8q8KDnb//EABwQAQACAwADAAAAAAAAAAAAAAEAESExQRCBof/aAAgBAQABPyGWNH2Y53Mv4HJV0TQCGSKBad6b8FkKM9E//9oADAMBAAIAAwAAABCr9nH/xAAXEQEBAQEAAAAAAAAAAAAAAAABEBEx/9oACAEDAQE/EOKi3J//xAAWEQADAAAAAAAAAAAAAAAAAAABIDH/2gAIAQIBAT8QuCH/xAAeEAEAAgIDAAMAAAAAAAAAAAABABEhMUFRcWGRsf/aAAgBAQABPxCodrZu/oCK10FzD0QuCuc/MFhVYbqhV9smAsVjCm+2HZjHgQD8gQCqhwS9032wdHkbxk9n/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;a fricking castle&quot;
        title=&quot;&quot;
        src=&quot;/static/d91a86c7ffbfe2b53f3d9b39969b9ea1/3cb18/frickingcastle.jpg&quot;
        srcset=&quot;/static/d91a86c7ffbfe2b53f3d9b39969b9ea1/0a254/frickingcastle.jpg 151w,
/static/d91a86c7ffbfe2b53f3d9b39969b9ea1/c8fe0/frickingcastle.jpg 303w,
/static/d91a86c7ffbfe2b53f3d9b39969b9ea1/3cb18/frickingcastle.jpg 605w,
/static/d91a86c7ffbfe2b53f3d9b39969b9ea1/d4b53/frickingcastle.jpg 853w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.fourhourworkweek.com/&quot;&gt;The Four-Hour Workweek&lt;/a&gt; irked me before I decided to read it and blew my mind once I chose to.&lt;/p&gt;
&lt;p&gt;Not only that, I blame that book for the fact that our company and our families are now days from packing up our office and moving to Europe for a month to work from &lt;a href=&quot;http://www.homeaway.com/vacation-rental/p89677&quot;&gt;a castle&lt;/a&gt; on Italy&apos;s Adriatic coast. &lt;/p&gt;
&lt;p&gt;Seriously. &lt;/p&gt;
&lt;p&gt;The title of the book irritated me. &lt;/p&gt;
&lt;p&gt;Why? Because I don’t want to work four hours a week. &lt;/p&gt;
&lt;p&gt;I want to throw myself into something I love and believe in, where I can create value and make a difference and learn and grow. &lt;/p&gt;
&lt;p&gt;That kind of business is really at the heart of the Four-Hour Workweek. Ferriss tells readers to quit being enslaved to their jobs, create a business to fund their dreams and go for it—now! &lt;/p&gt;
&lt;p&gt;Ferriss talks about dreamlining—focusing energy on making some amazing dream a reality as quickly as possible. If that means traveling the world, going on some grand adventure, or learning to be the best in the world at something, Ferriss offers productive paths to create a business that is your “muse”, cut all unnecessary expenses, smash all roadblocks, and go for it! &lt;/p&gt;
&lt;p&gt;You really should &lt;a href=&quot;http://www.amazon.com/4-Hour-Workweek-Expanded-Updated-Cutting-Edge/dp/0307465357/ref=sr_1_1?ie=UTF8&amp;#x26;qid=1299179135&amp;#x26;sr=8-1&quot;&gt;read the book&lt;/a&gt; if you haven&apos;t. &lt;/p&gt;
&lt;p&gt;I don’t want to oversimplify what is actually a book crammed tons of thought-provoking ideas, but a big piece of what Ferriss is talking about is making a lifestyle business for yourself. &lt;/p&gt;
&lt;p&gt;The term “lifestyle business” gets a bad rap sometimes, but I like how Products Hero &lt;a href=&quot;http://twitter.com/amyhoy/&quot;&gt;Amy Hoy&lt;/a&gt; puts it — “A lifestyle business is just a &lt;em&gt;profitable&lt;/em&gt; business!” &lt;/p&gt;
&lt;p&gt;Now, I already have a three-year profitable business that I built from the ground up with just me and the words “I AM DOING THIS” scrawled on a whiteboard. &lt;/p&gt;
&lt;p&gt;And I feel fairly confident at this point that if I really wanted to, I could step away and it could support me doing whatever I wanted for a time. &lt;/p&gt;
&lt;p&gt;But what if it wasn’t about me? Because it definitely isn’t in my book. &lt;/p&gt;
&lt;p&gt;Most importantly, &amp;#x26;yet is what it is because of &lt;a href=&quot;http://andyet.net/team/&quot;&gt;&lt;em&gt;who&lt;/em&gt; it is&lt;/a&gt;. And I’m just one small piece of that. &amp;#x26;yet might actually be a lifestyle business, but it isn’t &lt;em&gt;my&lt;/em&gt; lifestyle business... &lt;/p&gt;
&lt;p&gt;And, in fact, I realized that this is actually what &amp;#x26;yet is… &lt;/p&gt;
&lt;p&gt;It’s a team lifestyle business. &lt;/p&gt;
&lt;p&gt;When people ask me to describe &amp;#x26;yet, I always think about Nathan’s take on &amp;#x26;yet shortly after joining us. He summed it up thusly: &lt;/p&gt;
&lt;p&gt;“&amp;#x26;yet is a service to its employees.” [1]&lt;/p&gt;
&lt;p&gt;So rather than me simply creating a business and a machine that makes me money as the sole owner, it is instead a business whose profits are largely used to empower its employees’ growth, freedom, and enjoyment. And, by the way, I would give ridiculously high marks to our team’s resulting creativity and effective productivity. &lt;/p&gt;
&lt;p&gt;But back to Italy. &lt;/p&gt;
&lt;p&gt;Yes. We are going to exclusively rent an amazing centuries-old castle on a hill that sleeps 56 and has a view of the ocean on the eastern coast of Italy. &lt;/p&gt;
&lt;p&gt;We’re doing it because we want to, because we can, and because we believe the end results of our trip will be overwhelmingly positive. &lt;/p&gt;
&lt;p&gt;We’re doing it because we’ve always been fascinated by &lt;a href=&quot;http://twitter.com/#!/simonw&quot;&gt;Simon Willison’s&lt;/a&gt; &lt;a href=&quot;http://devfort.com/about/what-is-dev-fort&quot;&gt;/dev/fort&lt;/a&gt; idea. [2]&lt;/p&gt;
&lt;p&gt;We’re doing it because we realized it’s &lt;em&gt;cheaper&lt;/em&gt; to stay in a castle a little bit off the beaten path for a whole month than it is to stay in Rome for a week. &lt;/p&gt;
&lt;p&gt;We’re doing it because this is a huge enough opportunity that all of our team members decided we’d be willing to skip one paycheck to make it happen [3]&lt;/p&gt;
&lt;p&gt;We’re doing it this year because we want to do something like this next year too. &lt;/p&gt;
&lt;p&gt;And I&apos;ll be honest: all of the go-for-it encouragement and assumption-busting in The 4-Hour Workweek pushed it from whim to reality. &lt;/p&gt;
&lt;p&gt;So—thanks, Tim! Feel free to pop by the castle. I’d love to introduce my awesome team to you. &lt;/p&gt;
&lt;p&gt;And to everyone else: What’s your dream? What’s stopping you from making it happen immediately? &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you&apos;re doing something like this--or even if you want to, we want to hear about it!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We&apos;ll be sharing about our adventure and being darn honest about the experiment&apos;s successes and failures, so be sure to &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;Follow &amp;#x26;yet on Twitter&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/andyet/italy&quot;&gt;our team who&apos;s going&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;——— &lt;/p&gt;
&lt;p&gt;&lt;em&gt;[1] I have another blog post I want to unpack this statement a little more.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;[2] Incidentally, one day we want to do a /dev/train, inspired by our external teammate, &lt;a href=&quot;http://twitter.com/hjon&quot;&gt;Hjon&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;[3] The balance of which the company sneakily added back in to our wages by way of a permanent raise.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Re-using Backbone.js Models on the server with Node.js and Socket.io to build real-time apps]]></title><description><![CDATA[Quick intro, the hype and awesomeness that is NodeNode.js is pretty freakin' awesome, yes. But it's also been hyped up more than an Apple…]]></description><link>https://blog.andyet.com/2011/02/15/re-using-backbonejs-models-on-the-server-with-node/</link><guid isPermaLink="false">https://blog.andyet.com/2011/02/15/re-using-backbonejs-models-on-the-server-with-node/</guid><pubDate>Tue, 15 Feb 2011 11:31:09 GMT</pubDate><content:encoded>&lt;h3 id=&quot;quick-intro-the-hype-and-awesomeness-that-is-node&quot;&gt;&lt;a href=&quot;#quick-intro-the-hype-and-awesomeness-that-is-node&quot; aria-label=&quot;quick intro the hype and awesomeness that is node permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Quick intro, the hype and awesomeness that is Node&lt;/h3&gt;
&lt;p&gt;Node.js is pretty freakin&apos; awesome, yes. But it&apos;s also been hyped up more than an Apple gadget. As pointed out by Eric Florenzano &lt;a href=&quot;http://www.eflorenzano.com/blog/post/why-node-disappoints-me/&quot;&gt;on his blog&lt;/a&gt; a &lt;em&gt;LOT&lt;/em&gt; of the original excitement of server-side JS was due to the ability to share code between client and server. However, instead, the first thing everybody did is start porting all the existing tools and frameworks to node. Faster and better, perhaps, but it&apos;s still largely the same &apos;ol thing. Where&apos;s the paradigm shift? Where&apos;s the code reuse?!&lt;/p&gt;
&lt;p&gt;Basically, Node.js runs V8, the same JS engine as Chrome, and as such, it has fairly decent ECMA Script 5 support. Some of the stuff in &quot;5&quot; is super handy, such as all the iterator stuff &lt;code class=&quot;language-text&quot;&gt;forEach&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;map&lt;/code&gt;, etc. But – and it&apos;s a big &quot;but&quot; indeed – if you use those methods you&apos;re no longer able to use ANY of your code in older browsers, (read &quot;IE&quot;).&lt;/p&gt;
&lt;p&gt;So, &lt;em&gt;that&lt;/em&gt; is what makes &lt;a href=&quot;http://documentcloud.github.com/underscore/&quot;&gt;underscore.js&lt;/a&gt; so magical. It gives you simple JS fallbacks for non-supported ECMA Script 5 stuff. Which means, that if you use it in node (or a modern browser), it will still use the faster native stuff, if available, but if you use it in a browser that doesn&apos;t support that stuff &lt;em&gt;your code will still work&lt;/em&gt;. Code REUSE FTW!&lt;/p&gt;
&lt;p&gt;So what kind of stuff would we want to share between client and server?&lt;/p&gt;
&lt;h3 id=&quot;enter-backbonejs&quot;&gt;&lt;a href=&quot;#enter-backbonejs&quot; aria-label=&quot;enter backbonejs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Enter Backbone.js&lt;/h3&gt;
&lt;p&gt;A few months ago I got really into Backbone and wrote &lt;a href=&quot;http://andyet.net/blog/2010/oct/29/building-a-single-page-app-with-backbonejs-undersc/&quot;&gt;this introductory post about it&lt;/a&gt; that made the frontpage of &lt;a href=&quot;http://news.ycombinator.com/&quot;&gt;HN&lt;/a&gt;. Apparently, a LOT of other people were interested as well, and rightfully so; it&apos;s awesome. Luckily for us, &lt;a href=&quot;https://github.com/jashkenas&quot;&gt;Jeremy Askenas&lt;/a&gt; (primary author of &lt;a href=&quot;http://documentcloud.github.com/backbone/&quot;&gt;backbone&lt;/a&gt;, &lt;a href=&quot;http://documentcloud.github.com/underscore/&quot;&gt;underscore&lt;/a&gt;, &lt;a href=&quot;http://jashkenas.github.com/coffee-script/&quot;&gt;coffeescript&lt;/a&gt; and all around JS magician) is also a bit of a node guru and had the foresight to make both backbone and underscore usable in node, as modules. So once you&apos;ve installed &apos;em with &lt;code class=&quot;language-text&quot;&gt;npm&lt;/code&gt; you can just do this to use them on the server:
&lt;br&gt;
&lt;br&gt;
var _ = require(&apos;underscore&apos;)._,
backbone = require(&apos;backbone&apos;);
&lt;/p&gt;
&lt;h3 id=&quot;so-what-how-is-this-useful&quot;&gt;&lt;a href=&quot;#so-what-how-is-this-useful&quot; aria-label=&quot;so what how is this useful permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So what?! How is this useful?&lt;/h3&gt;
&lt;p&gt;State! What do I mean? As I mentioned in &lt;a href=&quot;http://andyet.net/blog/2010/oct/29/building-a-single-page-app-with-backbonejs-undersc/&quot;&gt;my introductory backbone.js post&lt;/a&gt;, if you&apos;ve structured your app &quot;correctly&quot; (granted, this my subjective opinion of &quot;correct&quot;), ALL your application state lives in the backbone models. In my code I go the extra step and store all the models for my app in a sort of &quot;root&quot; app model. I use this to store application settings as attributes and then any other models or collections that I&apos;m using in my app will be properties of this model. For example:
&lt;br&gt;
&lt;br&gt;
var AppModel = Backbone.Model.extend({
defaults: {
attribution: &quot;built by &amp;#x26;yet&quot;,
tooSexy: true
},
&lt;br&gt;
initialize: {
// some backbone collections
this.members = new MembersCollection();
this.coders = new CodersCollection();
&lt;br&gt;
// another child backbone model
this.user = new User();
}
});
&lt;/p&gt;
&lt;h3 id=&quot;unifying-application-state&quot;&gt;&lt;a href=&quot;#unifying-application-state&quot; aria-label=&quot;unifying application state permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Unifying Application State&lt;/h3&gt;
&lt;p&gt;By taking this approach and storing &lt;em&gt;all&lt;/em&gt; the application state in a single Backbone model, it&apos;s possible to write a serializer/deserializer to extract and re-inflate your entire application state. So that&apos;s what I did. I created two recursive functions that can export and import all the attributes of a nested backbone structure and I put them into a base class that looks something like this:
&lt;br&gt;
&lt;br&gt;
var BaseModel = Backbone.Model.extend({
// builds and return a simple object ready to be JSON stringified
xport: function (opt) {
var result = {},
settings = &lt;em&gt;({
recurse: true
}).extend(opt || {});
&lt;br&gt;
function process(targetObj, source) {
targetObj.id = source.id || null;
targetObj.cid = source.cid || null;
targetObj.attrs = source.toJSON();
_.each(source, function (value, key) {
// since models store a reference to their collection
// we need to make sure we don&apos;t create a circular refrence
if (settings.recurse) {
if (key !== &apos;collection&apos; &amp;#x26;&amp;#x26; source[key] instanceof Backbone.Collection) {
targetObj.collections = targetObj.collections || {};
targetObj.collections[key] = {};
targetObj.collections[key].models = [];
targetObj.collections[key].id = source[key].id || null;
_.each(source[key].models, function (value, index) {
process(targetObj.collections[key].models[index] = {}, value);
});
} else if (source[key] instanceof Backbone.Model) {
targetObj.models = targetObj.models || {};
process(targetObj.models[key] = {}, value);
}
}
});
}
&lt;br&gt;
process(result, this);
&lt;br&gt;
return result;
},
&lt;br&gt;
// rebuild the nested objects/collections from data created by the xport method
mport: function (data, silent) {
function process(targetObj, data) {
targetObj.id = data.id || null;
targetObj.set(data.attrs, {silent: silent});
// loop through each collection
if (data.collections) {
_.each(data.collections, function (collection, name) {
targetObj[name].id = collection.id;
Skeleton.models[collection.id] = targetObj[name];
_.each(collection.models, function (modelData, index) {
var newObj = targetObj[name].&lt;/em&gt;add({}, {silent: silent});
process(newObj, modelData);
});
});
}
&lt;br&gt;
if (data.models) {
_.each(data.models, function (modelData, name) {
process(targetObj[name], modelData);
});
}
}
&lt;br&gt;
process(this, data);
&lt;br&gt;
return this;
}
});
&lt;/p&gt;
&lt;p&gt;So, now we can quickly and easily turn an entire application&apos;s state into a simple JS object that can be JSON stringified and restored or persisted in a database, or in localstorage, or sent across the wire. Also, if we have these serialization function in our base model we can selectively serialize any portion of the nested application structure.&lt;/p&gt;
&lt;p&gt;Backbone models are a &lt;em&gt;great&lt;/em&gt; way to store and observe state.&lt;/p&gt;
&lt;p&gt;So, here&apos;s the kicker: &lt;strong&gt;USE IT ON THE SERVER!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;how-to-build-models-that-work-on-the-server-and-the-client&quot;&gt;&lt;a href=&quot;#how-to-build-models-that-work-on-the-server-and-the-client&quot; aria-label=&quot;how to build models that work on the server and the client permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;How to build models that work on the server and the client&lt;/h3&gt;
&lt;p&gt;The trick here is to include some logic that lets the file figure out whether it&apos;s being used as a &lt;a href=&quot;http://www.commonjs.org/&quot;&gt;CommonJS&lt;/a&gt; module of if it&apos;s just in a script tag.&lt;/p&gt;
&lt;p&gt;There are a few different ways of doing this. For example you can do something like this in your models file:
&lt;br&gt;
&lt;br&gt;
(function () {
var server = false,
MyModels;
if (typeof exports !== &apos;undefined&apos;) {
MyModels = exports;
server = true;
} else {
MyModels = this.MyModels = {};
}
&lt;br&gt;
MyModels.AppModel...
&lt;br&gt;
})()
&lt;/p&gt;
&lt;p&gt;Just be aware that any external dependencies will be available if you&apos;re in the browser and you&apos;ve got other &lt;code class=&quot;language-text&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags defining those globals, but anything you need on the server will have to be explicitly imported.&lt;/p&gt;
&lt;p&gt;Also, notice that I&apos;m setting a &lt;code class=&quot;language-text&quot;&gt;server&lt;/code&gt; variable. This is because there are certain things I may want to do in my code on the server that won&apos;t happen in the client. Doing this will make it easy to check where I am (we try to keep this to a minimum though, code-reuse is the goal).&lt;/p&gt;
&lt;h3 id=&quot;state-syncing&quot;&gt;&lt;a href=&quot;#state-syncing&quot; aria-label=&quot;state syncing permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;State syncing&lt;/h3&gt;
&lt;p&gt;So, if we go back to thinking about the client/server relationship, we can now keep an inflated Backbone model living in memory on the server and if the server gets a page request from the browser we can export the state from the server and use that to rebuild the page to match the current state on the server. Also, if we set up event listeners properly on our models we can actually listen for changes and send changes back and forth between client/server to keep the two in sync.&lt;/p&gt;
&lt;h3 id=&quot;taking-this-puppy-realtime&quot;&gt;&lt;a href=&quot;#taking-this-puppy-realtime&quot; aria-label=&quot;taking this puppy realtime permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Taking this puppy realtime&lt;/h3&gt;
&lt;p&gt;None of this is particularly interesting unless we have the ability to send data both ways – from client to server &lt;em&gt;and&lt;/em&gt; more importantly from server to client. We build real-time web apps at &amp;#x26;&lt;a href=&quot;http://andyet.net&quot;&gt;yet&lt;/a&gt;–that&apos;s what we do. Historically, that&apos;s all been XMPP based. XMPP is awesome, but XMPP speaks XML. While JavaScript &lt;em&gt;can&lt;/em&gt; do XML, it&apos;s certainly simpler to not have to do that translation of XMPP stanzas into something JS can deal with. These days, we&apos;ve been doing more and more with &lt;a href=&quot;http://socket.io/&quot;&gt;Socket.io&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-magical-socketio&quot;&gt;&lt;a href=&quot;#the-magical-socketio&quot; aria-label=&quot;the magical socketio permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The magical Socket.io&lt;/h3&gt;
&lt;p&gt;Socket.io is to Websockets what jQuery is to the DOM. Basically, it handles browser shortcomings for you and gives you a simple unified API. In short, &lt;a href=&quot;http://socket.io&quot;&gt;socket.io&lt;/a&gt; is a seamless transport mechanism from node.js to the browser. It will use websockets if supported and fall back to one of 5 transport mechanisms. Ultimately, it goes all the way back to IE 5.5! Which is just freakin&apos; ridiculous, but at the same time, awesome.&lt;/p&gt;
&lt;p&gt;Once you figure out how to set up &lt;a href=&quot;http://socket.io/&quot;&gt;socket.io&lt;/a&gt;, it&apos;s fairly straightforward to send messages back and forth.&lt;/p&gt;
&lt;p&gt;So on the server-side we do something like this on the new connection:
&lt;br&gt;
&lt;br&gt;
io.on(&apos;connection&apos;, function(client){
var re = /(?:connect.sid=)[.\w%]+/;
var cookieId = re.exec(client.request.headers.cookie)[0].split(&apos;=&apos;)[1]
var clientModel = clients.get(cookieId)
&lt;br&gt;
if (!clientModel) {
clientModel = new models.ClientModel({id: cookieId});
clients.add(clientModel);
}
&lt;br&gt;
// store some useful info
clientModel.client = client;
&lt;br&gt;
client.send({
event: &apos;initial&apos;,
data: clientModel.xport(),
templates:
});
&lt;br&gt;
...
&lt;/p&gt;
&lt;p&gt;So, on the server when a new client connection is made, we immediately send the full app state:
&lt;br&gt;
&lt;br&gt;
io.on(&apos;connection&apos;, function(client) {
client.send({
event: &apos;initial&apos;,
data: appModel.xport()
});
};
&lt;/p&gt;
&lt;p&gt;For simplicity, I&apos;ve decided to keep the convention of sending a simple event name and the data just so my client can know what to do with the data.&lt;/p&gt;
&lt;p&gt;So, the client then has something like this in its message handler.
&lt;br&gt;
&lt;br&gt;
socket.on(&apos;message&apos;, function (data) {
switch (data.event) {
case &apos;initial&apos;:
app.model.mport(data.data);
break;
case &apos;change&apos;
&lt;br&gt;
...&lt;br&gt;
&lt;br&gt;
}
&lt;br&gt;
&lt;br&gt;
});
&lt;/p&gt;
&lt;p&gt;So, in one fell swoop, we&apos;ve completely synced state from the server to the client. In order to handle multiple connections and shared state, you&apos;ll obviously have to add some additional complexity in your server logic so you send the right state to the right user. You can also wait for the client to send some other identifying information, or whatnot. For the purposes of this post I&apos;m trying to keep it simple (it&apos;s long already).&lt;/p&gt;
&lt;h3 id=&quot;syncing-changes&quot;&gt;&lt;a href=&quot;#syncing-changes&quot; aria-label=&quot;syncing changes permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Syncing changes&lt;/h3&gt;
&lt;p&gt;JS is built to be event driven and frankly, that&apos;s the magic of Backbone models and views. There may be multiple views that respond to events, but ultimately, all your state information lives in &lt;em&gt;one&lt;/em&gt; place. This is really important to understand. If you don&apos;t know what I mean, go back and read &lt;a href=&quot;http://andyet.net/blog/2010/oct/29/building-a-single-page-app-with-backbonejs-undersc/&quot;&gt;my previous post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So, now what if something changes on the server? Well, one option would be to just send the full state to the clients we want to sync each time. In some cases that may not be so bad – especially if the app is fairly light, the raw state data is pretty small as well. But still, that seems like overkill to me. So what I&apos;ve been doing is just sending the model that changed. So I added the following &lt;code class=&quot;language-text&quot;&gt;publishChange&lt;/code&gt; method to my base model:
&lt;br&gt;
&lt;br&gt;
publishChange: function (model, collection) {
var event = {};
&lt;br&gt;
if (model instanceof Backbone.Model) {
event = {
event: &apos;change&apos;,
model: {
data: model.xport({recurse: false}),
id: model.id
}
}
} else {
console.log(&apos;event was not a model&apos;, e);
}
&lt;br&gt;
this.trigger(&apos;publish&apos;, event);
},
&lt;/p&gt;
&lt;p&gt;Then added something like this to each model&apos;s init method:
&lt;br&gt;
&lt;br&gt;
initialize: function () {
this.bind(&apos;change&apos;, _(this.publishChange).bind(this));
}
&lt;/p&gt;
&lt;p&gt;So now, we have an event type in this case &lt;code class=&quot;language-text&quot;&gt;change&lt;/code&gt; and then we&apos;ve got the model information. Now you may be wondering how we&apos;d know which model to update on the other end of the connection. The trick is the &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;. What I&apos;ve done so solve this problem is to always generate a UUID and set it as the &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt; when any model or collection is instantiated on the server. Then, always register models and collections in a global lookup hash by their &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;. That way we can look up any model or collection in the hash and just &lt;code class=&quot;language-text&quot;&gt;set&lt;/code&gt; all our data on it. Now my client controller can listen for &lt;code class=&quot;language-text&quot;&gt;publish&lt;/code&gt; events and send them across the wire with just an &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;. Here&apos;s my register function on my base model (warning, it&apos;s a bit hackish):
&lt;br&gt;
&lt;br&gt;
register: function () {
var self = this;
if (server) {
var id = uuid();
this.id = id;
this.set({id: id});
}
&lt;br&gt;
if (this.id &amp;#x26;&amp;#x26; !Skeleton.models[this.id]) Skeleton.models[this.id] = this;
&lt;br&gt;
this.bind(&apos;change:id&apos;, function (model) {
if (!Skeleton.models[this.id]) Skeleton.models[model.id] = self;
});
},
&lt;/p&gt;
&lt;p&gt;Then, in each model&apos;s &lt;code class=&quot;language-text&quot;&gt;initialize&lt;/code&gt; method, I call register and I have a lookup:
&lt;br&gt;
&lt;br&gt;
initialize: function () {
this.register();&lt;br&gt;
}
&lt;/p&gt;
&lt;p&gt;So now, my server will generate a UUID and when the model is sent to the client that &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt; will be the same. Now we can always get any model, no matter how far it&apos;s nested by checking the &lt;code class=&quot;language-text&quot;&gt;Skeleton.models&lt;/code&gt; hash. It&apos;s not hard to deduce that you could take a similar approach for handling &lt;code class=&quot;language-text&quot;&gt;add&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;remove&lt;/code&gt; events as long as you&apos;ve got a way to look up the collections on the other end.&lt;/p&gt;
&lt;h3 id=&quot;so-how-should-this-be-used&quot;&gt;&lt;a href=&quot;#so-how-should-this-be-used&quot; aria-label=&quot;so how should this be used permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;So how should this be used?&lt;/h3&gt;
&lt;p&gt;Well there&apos;s are three choices that I see.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Send model changes from either the server or the client in the same way. Imagine we&apos;re starting with an identical state on the server and client. If we now modify the model in place on the client, the &lt;code class=&quot;language-text&quot;&gt;publish&lt;/code&gt; event would be triggered and its &lt;code class=&quot;language-text&quot;&gt;change&lt;/code&gt; event would be sent to the server. The change would be &lt;code class=&quot;language-text&quot;&gt;set&lt;/code&gt; to the corresponding model on the server, which would then immediately trigger another &lt;code class=&quot;language-text&quot;&gt;change&lt;/code&gt; event, this time on the server echoing back the change to the client. At that point the loop would die because the &lt;code class=&quot;language-text&quot;&gt;change&lt;/code&gt; isn&apos;t actually different than the current state so no event would be triggered. The downside with this approach is that it&apos;s not as fault tolerant of flaky connections &lt;em&gt;and&lt;/em&gt; it&apos;s a bit on the noisy side since each change is getting sent and then echoed back. The advantage of this approach is that you can simply change the local model like you normally would in backbone and your changes would just be synced. Also, the local view would immediately reflect the change since it&apos;s happening locally.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The other, possibly superior, approach is to treat the server as the authority and broadcast all the changes from the server. Essentially, you would just build the &lt;code class=&quot;language-text&quot;&gt;change&lt;/code&gt; event in the client rather than actually setting it locally. That way you leave it up to the server to actually make changes and then the &lt;em&gt;real&lt;/em&gt; change events would all flow from the server to the client. With this approach, you&apos;d actually &lt;code class=&quot;language-text&quot;&gt;set&lt;/code&gt; the change events you got from the server on the client-side, your views would use those changes to update, but your controller on the client-side wouldn&apos;t send changes back across the wire.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The last approach is just a hybrid of the other two. Essentially, there&apos;s nothing stopping you from selectively doing both. In theory, you can sync the trivial state information for example simple UI state (whether an item in a list is selected or not) using method #1 and then do more important interactions by sending commands to the server.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In my experiments option 2 seems to work the best. By treating the server as the ultimate authority, you save yourself a lot of headaches. To accommodate this I simply added one more method to my base model class called &lt;code class=&quot;language-text&quot;&gt;setServer&lt;/code&gt;. It builds a change event and sends it through our socket. So now, in my views on the client, when I&apos;m responding to a user action instead of calling &lt;code class=&quot;language-text&quot;&gt;set&lt;/code&gt; on the model I simply call &lt;code class=&quot;language-text&quot;&gt;setServer&lt;/code&gt; and pass it a hash of key/value pairs just like I would for a normal &lt;code class=&quot;language-text&quot;&gt;set&lt;/code&gt;.
&lt;br&gt;
&lt;br&gt;
setServer: function(attrs, options) {
socket.send({
event: &apos;set&apos;,
id: this.id,
change: attrs
});
}
&lt;/p&gt;
&lt;h3 id=&quot;why-is-this-whole-thing-awesome&quot;&gt;&lt;a href=&quot;#why-is-this-whole-thing-awesome&quot; aria-label=&quot;why is this whole thing awesome permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Why is this whole thing awesome?&lt;/h3&gt;
&lt;p&gt;It lets you build really awesome stuff! Using this approach we send very small changes over an already established connection, we can very quickly synchronize state from one client to the other or the server can get updates from an external data source, modify the model on the server and those changes would immediately be sent to the connected clients. &lt;/p&gt;
&lt;p&gt;Best of all – it&apos;s fast. Now, you can just write your views like you normally would in a Backbone.js app.&lt;/p&gt;
&lt;p&gt;Obviously, there are other problems to be solved. For example, it all gets a little bit trickier when dealing with a multiple states. Say, for instance you have a portion of application state that you want to sync globally with all users and a portion that you just want to sync with other instances of the same user, or the same team, etc. Then you have to either do multiple socket channels (which I understand Guillermo is working on), or you have to sync all the state and let your views sort our what to respond to.&lt;/p&gt;
&lt;p&gt;Also, there&apos;s persistence and scaling questions some of which we&apos;ve got solutions for, some of which, we don&apos;t. I&apos;ll save that for another post. This architecture is clearly not perfect for every application. However, in the use cases where it fits, it&apos;s quite powerful. I&apos;m neck-deep in a couple of projects where I&apos;m explore the possibilities of this approach and I&apos;ve gotta say, I&apos;m very excited about the results. I&apos;m also working on putting together a bit of a real-time framework built on the ideas in this post. I&apos;m certainly not alone in these pursuits, it&apos;s just so cool to see more and more people innovating and building cool stuff with real-time technologies. I&apos;m thankful for any feedback you&apos;ve got, good or bad.&lt;/p&gt;
&lt;p&gt;If you have thoughts or questions, I&apos;m &lt;a href=&quot;http://twitter.com/henrikjoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; on twitter. Also, my buddy/co-worker &lt;a href=&quot;http://twitter.com/fritzy&quot;&gt;@fritzy&lt;/a&gt; and I have started doing a video podcast about this sort of stuff called &lt;a href=&quot;http://keepingitrealtime.com&quot;&gt;Keeping It Realtime&lt;/a&gt;. And, be sure to follow &lt;a href=&quot;http://twitter.com/andyet&quot;&gt;@andyet&lt;/a&gt; and honestly, the whole &amp;#x26;&lt;a href=&quot;http://andyet.net/team/&quot;&gt;yet team&lt;/a&gt; for more stuff related to real-time web dev. We&apos;re planning some interesting things that we&apos;ll be announcing shortly. Cheers.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;If you&apos;re building a single page app, keep in mind that &amp;#x26;yet offers consulting, training and development services. Hit us up (&lt;a href=&quot;mailto:henrik@andyet.net&quot;&gt;henrik@andyet.net&lt;/a&gt;) and tell us what we can do to help.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[We're sponsoring nodeconf?! Heck yes!]]></title><description><![CDATA[If you'd asked most developers 5 years ago, most of them would have said: "Why would anyone want to write JS on the server?!" The luddites…]]></description><link>https://blog.andyet.com/2011/01/31/were-sponsoring-nodeconf-heck-yes/</link><guid isPermaLink="false">https://blog.andyet.com/2011/01/31/were-sponsoring-nodeconf-heck-yes/</guid><pubDate>Mon, 31 Jan 2011 09:46:02 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a32b08b6bb75a69086d62c12e9e455d7/a6d36/node_0002_NODECONF2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 27.1523178807947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsSAAALEgHS3X78AAABLElEQVQY02NgwAEeP37MzEAkmLjQS2fyYu+yWav9pUAatYA4CYiNgdgDiN2B2O7Ro0ezgTgSyHa7f+8RR/9CV9/Ji31iJy/x9pq0yDt6ylKfgDlrA/JAhs3bELhq6jKfpp45HlwgA92BGguBeC2QnQzEXUDcDuSnPnr08MLL558ajp9bunTKCruS2WuCCmevDZg1e41/2YJNQU9nr/Wvnrc+sGb+xsBeoAVaMK/5AnEWEC8E4mYgboXSPUADtz9/9jb54tWDU+dvDJg6Y6VfNtBb/TNW+TUDXbUHyM6csy5gwtz1AfOnr/S1gRnIAcT8QBeBaDEg5gViHiAWBWKu+w9ui4DU9cz2kO6Y7iZf3+co3DjBSTq/xlKkpstBsrLdTqa6016+psteAKQOAPIowW7dpc0EAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;node.conf&quot;
        title=&quot;&quot;
        src=&quot;/static/a32b08b6bb75a69086d62c12e9e455d7/90cbd/node_0002_NODECONF2.png&quot;
        srcset=&quot;/static/a32b08b6bb75a69086d62c12e9e455d7/29fe9/node_0002_NODECONF2.png 151w,
/static/a32b08b6bb75a69086d62c12e9e455d7/6728c/node_0002_NODECONF2.png 303w,
/static/a32b08b6bb75a69086d62c12e9e455d7/90cbd/node_0002_NODECONF2.png 605w,
/static/a32b08b6bb75a69086d62c12e9e455d7/a6d36/node_0002_NODECONF2.png 650w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;d asked most developers 5 years ago, most of them would have said: &quot;Why would anyone want to write JS on the server?!&quot; The &lt;a href=&quot;/team/nathan/&quot;&gt;luddites&lt;/a&gt; still do.&lt;/p&gt;
&lt;p&gt;But we, at &amp;#x26;yet, have fallen in love with &lt;a href=&quot;http://nodejs.org&quot;&gt;node&lt;/a&gt;. Our particular schtick is the real-time web (see &lt;a href=&quot;http://keepingitrealtime.com&quot;&gt;our podcast&lt;/a&gt;). We&apos;ve been building real-time web apps for a while, mostly with XMPP and &lt;a href=&quot;http://code.stanziq.com/strophe/&quot;&gt;Strophe.js&lt;/a&gt;. Recently, however we&apos;ve started using node + &lt;a href=&quot;http://socket.io/&quot;&gt;socket.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Frankly, we couldn&apos;t be happier and can&apos;t wait to see what the future holds as these technologies continue to mature.&lt;/p&gt;
&lt;p&gt;We&apos;re humbled and excited to get to be a part of what promises to be an &lt;a href=&quot;http://nodeconf.com&quot;&gt;amazing conference&lt;/a&gt;. Given that it sold out in about 4 minutes, clearly we&apos;re not the only ones!&lt;/p&gt;
&lt;p&gt;See you there!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Building a single page app with Backbone.js, underscore.js and jQuery]]></title><description><![CDATA[OverviewWe've been finding ourselves building more and more JS heavy apps here at &yet. Until recently, we've pretty much invented a custom…]]></description><link>https://blog.andyet.com/2010/10/29/building-a-single-page-app-with-backbonejs-undersc/</link><guid isPermaLink="false">https://blog.andyet.com/2010/10/29/building-a-single-page-app-with-backbonejs-undersc/</guid><pubDate>Fri, 29 Oct 2010 14:33:29 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/96fa4d0c2581dfe244d63787a0b7d92e/41d3c/backbone-graphic.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 490px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 63.57615894039734%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsSAAALEgHS3X78AAABj0lEQVQoz4VSW0/CMBjdf/cP+OCj8c2YAE+AxEQTjC8qoiZswwGl7ditsLLB2OZu3SxDoyLIydemac/J1/YcoTiEvKydEL5Jf1EULC8P1ovNxi+acLBzyIqI7ekcx3EURb7ve54XhmFQYuX7rusmUXRj+BcDeizSV+Klob8KQkrnQRA6jrtYLIQxRBDhvjIQJRmM4WA4UviACA2HdWlSE1Wq4XYfn3QQhpAzEVa5RFEGD52uMBwBdaKNIQYAjgDkB7LchxBjhE6fAELYNnQCwdmLCrA2mWimRXjRudN9fhF007JtSqljkalumvzyNp0bhIRLt/5mtMBMQnpVVCuS7tgzw7S4XlU1UZY1TRd+WsLBvhab+ZqyxpTJq22z+FczxgRW7rft9I6u60h5r1tJVlqkBllVj7/YRZ7/En/6HLOit2TAZ71l1iBpw0o2jK6bvXlrl1i+PyT3Tta00nMtrhnJo5O1SFLRE2mZzUp/8/0RWIuNd8bFTSu5tdNLkl5NU/4KGPzXczueO1KdHwjfB/6o4SrNwBtmAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;a backbone&quot;
        title=&quot;&quot;
        src=&quot;/static/96fa4d0c2581dfe244d63787a0b7d92e/41d3c/backbone-graphic.png&quot;
        srcset=&quot;/static/96fa4d0c2581dfe244d63787a0b7d92e/29fe9/backbone-graphic.png 151w,
/static/96fa4d0c2581dfe244d63787a0b7d92e/6728c/backbone-graphic.png 303w,
/static/96fa4d0c2581dfe244d63787a0b7d92e/41d3c/backbone-graphic.png 490w&quot;
        sizes=&quot;(max-width: 490px) 100vw, 490px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;overview&quot;&gt;&lt;a href=&quot;#overview&quot; aria-label=&quot;overview permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Overview&lt;/h3&gt;
&lt;p&gt;We&apos;ve been finding ourselves building more and more JS heavy apps here at &amp;#x26;yet. Until recently, we&apos;ve pretty much invented a custom app architecture for each one.&lt;/p&gt;
&lt;p&gt;Not surprisingly, we&apos;re finding ourselves solving similar problems repeatedly.&lt;/p&gt;
&lt;p&gt;On the server side, we use django to give us an MVC structure to follow. But there&apos;s no obvious structure to your client-side code. There are some larger libraries that give you this, but usually have a ton of widgets etc. I&apos;m talking about solutions like &lt;a href=&quot;http://www.sproutcore.com/&quot;&gt;Sproutcore&lt;/a&gt;, &lt;a href=&quot;http://developer.yahoo.com/yui/&quot;&gt;YUI&lt;/a&gt;, or &lt;a href=&quot;http://code.google.com/closure/&quot;&gt;Google Closure&lt;/a&gt; and there are toolkits like &lt;a href=&quot;http://code.google.com/webtoolkit/&quot;&gt;GWT&lt;/a&gt; and &lt;a href=&quot;http://cappuccino.org/&quot;&gt;Cappuccino&lt;/a&gt; that let you compile other code to JS.&lt;/p&gt;
&lt;p&gt;But for those of us who want to lovingly craft the UI &lt;em&gt;exactly&lt;/em&gt; how we want them in the JavaScript we know and love, and yet crave quick lightweight solutions, those toolkits feel like overkill.&lt;/p&gt;
&lt;p&gt;Recently something called &lt;a href=&quot;http://documentcloud.github.com/backbone/&quot;&gt;Backbone.js&lt;/a&gt; hit my &quot;three tweet threshold&quot; I decided to take a look. Turns out it&apos;s a winner in my book and I&apos;ll explain why and how we used it.&lt;/p&gt;
&lt;h3 id=&quot;the-problem&quot;&gt;&lt;a href=&quot;#the-problem&quot; aria-label=&quot;the problem permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Problem&lt;/h3&gt;
&lt;p&gt;There are definitely some challenges that come with building complex, single-page apps, not the least of which is managing an ever increasing amount of code running in the same page. Also, since JavaScript has no formal classes there is no self-evident approach for structuring an entire application.&lt;/p&gt;
&lt;p&gt;As a result of these problems new JS devs trying to build these apps typically goes through a series of realizations that goes something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get all excited about jQuery and attempt to use the DOM to store data and application state.&lt;/li&gt;
&lt;li&gt;Realizing the first approach gets really tricky once you have more than a few things to keep track of and so instead you attempt to store that state in some type of JS model.&lt;/li&gt;
&lt;li&gt;Realizing that binding model changes to the UI can get messy if you call functions directly from your model setters/getters. You know you have to react to model changes in the UI somehow but not really knowing where to do those DOM manipulations and ending up something that&apos;s looking more and more like spaghetti code.&lt;/li&gt;
&lt;li&gt;Building some type of app structure/framework to solve these problems.&lt;/li&gt;
&lt;li&gt;And... finally realizing that someone&apos;s already solved many of these problems for you (and open sourced their code).&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;the-goals&quot;&gt;&lt;a href=&quot;#the-goals&quot; aria-label=&quot;the goals permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Goals&lt;/h3&gt;
&lt;p&gt;So, how do we want our app to behave? Here are the ideals as I see them.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All state/models for your app should live in one place.&lt;/li&gt;
&lt;li&gt;Any change in that model should be automatically reflected in the UI, whether that&apos;s in one place or many.&lt;/li&gt;
&lt;li&gt;Clean/maintainable code structure.&lt;/li&gt;
&lt;li&gt;Writing as little &quot;glue code&quot; as possible.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;enter-backbonejs&quot;&gt;&lt;a href=&quot;#enter-backbonejs&quot; aria-label=&quot;enter backbonejs permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Enter Backbone.js&lt;/h3&gt;
&lt;p&gt;Backbone doesn&apos;t attempt to give you widgets or application objects or even &lt;em&gt;really&lt;/em&gt; give you views. It basically gives you a few key objects to help you structure your code. Namely, Models, Collections and Views. Ultimately what it provides is some basic tools that you can use to build a clean MVC app in the client. We get some useful base objects for those and an event architecture for handling changes. Let&apos;s take a look at each of those.&lt;/p&gt;
&lt;h4 id=&quot;the-model-object&quot;&gt;&lt;a href=&quot;#the-model-object&quot; aria-label=&quot;the model object permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The Model object&lt;/h4&gt;
&lt;p&gt;The model object just gives you a way to set and retrieve arbitrary attributes. So, all you &lt;em&gt;really&lt;/em&gt; need to create a fully functioning and useful model is the following:
&lt;br&gt;
&lt;br&gt;
var Movie = Backbone.Model.extend({});&lt;/p&gt;
&lt;p&gt;Now you can instantiate, and set and get attributes all you want:
&lt;br&gt;
&lt;br&gt;
matrix = new Movie();
&lt;br&gt;
matrix.set({
title: &quot;The Matrix&quot;,
format: &quot;dvd&apos;
});
&lt;br&gt;
matrix.get(&apos;title&apos;);&lt;/p&gt;
&lt;p&gt;You can also pass it attributes directly when you instantiate like so:
&lt;br&gt;
&lt;br&gt;
matrix = new Movie({
title: &quot;The Matrix&quot;,
format: &quot;dvd&apos;
});&lt;/p&gt;
&lt;p&gt;If you need to enforce that certain required attributes when you build it, you can do so by providing an &lt;code class=&quot;language-text&quot;&gt;initialize()&lt;/code&gt; function to provide some initial checks. By convention the initialize function gets called with the arguments you pass the constructor.
&lt;br&gt;
&lt;br&gt;
var Movie = Backbone.Model.extend({
initialize: function (spec) {
if (!spec || !spec.title || !spec.format) {
throw &quot;InvalidConstructArgs&quot;;
}
&lt;br&gt;
// we may also want to store something else as an attribute
// for example a unique ID we can use in the HTML to identify this
// item&apos;s element. We can use the models &apos;cid&apos; or &apos;client id for this&apos;.
this.set({
htmlId: &apos;movie_&apos; + this.cid
})
}
});&lt;/p&gt;
&lt;p&gt;You can also define a &lt;code class=&quot;language-text&quot;&gt;validate()&lt;/code&gt; method. This will get called anytime you set attributes and you can use it to validate your attributes (surprise!). If the &lt;code class=&quot;language-text&quot;&gt;validate()&lt;/code&gt; method returns something it won&apos;t set that attribute.
&lt;br&gt;
&lt;br&gt;
var Movie = Backbone.Model.extend({
validate: function (attrs) {
if (attrs.title) {
if (!_.isString(attrs.title) || attrs.title.length === 0 ) {
return &quot;Title must be a string with a length&quot;;
}
}
}
});&lt;/p&gt;
&lt;p&gt;Ok, so there&apos;s a quite a few more goodies you get for free from the models. But I&apos;m trying to give an overview, not replace the documentation (which is quite good). Let&apos;s move on.&lt;/p&gt;
&lt;h4 id=&quot;collections&quot;&gt;&lt;a href=&quot;#collections&quot; aria-label=&quot;collections permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Collections&lt;/h4&gt;
&lt;p&gt;Backbone collections are just an ordered collection of models of a certain type. Rather than just storing your models in a JS Array, a collection gives you a lot of other nice functionality for free. Functionality such as conveniences for retrieving models and a way to always keep in sorted according to the rules you define in a &lt;code class=&quot;language-text&quot;&gt;comparator()&lt;/code&gt; function. &lt;/p&gt;
&lt;p&gt;Also, after you tell a collection which type of model it holds then adding a new item to the collection is a simple as:
&lt;br&gt;
&lt;br&gt;
// define our collection
var MovieLibrary = Backbone.Collection.extend({
model: Movie,
&lt;br&gt;
initialize: function () {
// somthing
}
});
&lt;br&gt;
var library = new MovieLibarary();
&lt;br&gt;
// you can add stuff by creating the model first
var dumb&lt;em&gt;and&lt;/em&gt;dumber = new Movie({
title: &quot;Dumb and Dumber&quot;,
format: &quot;dvd&quot;
});
&lt;br&gt;
library.add(dumb&lt;em&gt;and&lt;/em&gt;dumber);
&lt;br&gt;
// or even by adding the raw attributes
library.add({
title: &quot;The Big Lebowski&quot;,
format: &quot;VHS&quot;
});&lt;/p&gt;
&lt;p&gt;Again, there&apos;s a lot more goodies in Collections, but their main thing is solving a lot of the common problems for maintaining an ordered collection of models.&lt;/p&gt;
&lt;h4 id=&quot;views&quot;&gt;&lt;a href=&quot;#views&quot; aria-label=&quot;views permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Views&lt;/h4&gt;
&lt;p&gt;Here&apos;s where your DOM manipulation (read jQuery) takes place. In fact, I use that as a compliance check: The &lt;em&gt;only&lt;/em&gt; files that should have jQuery as a dependency are Views.&lt;/p&gt;
&lt;p&gt;A view is simply a convention for drawing changes to a model to the browser. This is where you directly manipulate the HTML. For the initial rendering (when you first add a new model) you really need some sort of useful client-side templating solution. My personal biased preference is to use &lt;a href=&quot;http://github.com/andyet/ICanHaz.js&quot;&gt;ICanHaz.js&lt;/a&gt; and &lt;a href=&quot;http://github.com/janl/mustache.js/&quot;&gt;Mustache.js&lt;/a&gt; to store and retrieve them. (If you&apos;re interested there&apos;s &lt;a href=&quot;http://github.com/andyet/ICanHaz.js&quot;&gt;more on ICanHaz.js on github&lt;/a&gt;.) But then, your view just listens and responds to changes in the model.&lt;/p&gt;
&lt;p&gt;Here&apos;s a simple view for our Movie items:
&lt;br&gt;
&lt;br&gt;
var MovieView = Backbone.View.extend({
initialize: function (args) {
_.bindAll(this, &apos;changeTitle&apos;);
&lt;br&gt;
this.model.bind(&apos;change:title&apos;, this.changeTitle);
},
&lt;br&gt;
events: {
&apos;click .title&apos;: &apos;handleTitleClick&apos;
},
&lt;br&gt;
render: function () {
// &quot;ich&quot; is ICanHaz.js magic
this.el = ich.movie(this.model.toJSON());
&lt;br&gt;
return this;
},
&lt;br&gt;
changeTitle: function () {
this.$(&apos;.title&apos;).text(this.model.get(&apos;title&apos;));
},
&lt;br&gt;
handleTitleClick: function () {
alert(&apos;you clicked the title: &quot; + this.model.get(&apos;title&quot;));
}
});&lt;/p&gt;
&lt;p&gt;So this view handles two kinds of events. First, the &lt;code class=&quot;language-text&quot;&gt;events&lt;/code&gt; attribute links user events to handlers. In this case, handling the click for anything with a class of &lt;code class=&quot;language-text&quot;&gt;title&lt;/code&gt; in the template. Also, this just makes sure that any changes to the model will automatically update the html, therein lies a &lt;em&gt;lot&lt;/em&gt; of the power of backbone.&lt;/p&gt;
&lt;h3 id=&quot;putting-it-all-together&quot;&gt;&lt;a href=&quot;#putting-it-all-together&quot; aria-label=&quot;putting it all together permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Putting it all together&lt;/h3&gt;
&lt;p&gt;So far we&apos;ve talked about the various pieces. Now let&apos;s talk about an approach for assembling an entire app.&lt;/p&gt;
&lt;h4 id=&quot;the-global-controller-object&quot;&gt;&lt;a href=&quot;#the-global-controller-object&quot; aria-label=&quot;the global controller object permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The global controller object&lt;/h4&gt;
&lt;p&gt;Although you may be able to get away with just having your main app controller live inside the AppView object, I didn&apos;t like storing my model objects in the view. So I created a global controller object to store everything. For this I create a simple a singleton object named whatever my app is named. So, to continue our example I might look something like this.
&lt;br&gt;
&lt;br&gt;
var MovieAppController = {
init: function (spec) {
// default config
this.config = {
connect: true
};
&lt;br&gt;
// extend our default config with passed in object attributes
_.extend(this.config, spec);
&lt;br&gt;
this.model = new MovieAppModel({
nick: this.config.nick,
account: this.config.account,
jid: this.config.jid,
boshUrl: this.config.boshUrl
});
this.view = new MovieAppView({model: this.model});
&lt;br&gt;
// standalone modules that respond to document events
this.sm = new SoundMachine();
&lt;br&gt;
return this;
},
&lt;br&gt;
// any other functions here should be events handlers that respond to
// document level events. In my case I was using this to respond to incoming XMPP
// events. So the logic for knowing what those meant and creating or updating our
// models and collections lived here.
handlePubSubUpdate: function () {};
};&lt;/p&gt;
&lt;p&gt;Here you can see that we&apos;re storing our application model that holds all our other models and collections and our application view.&lt;/p&gt;
&lt;p&gt;Our app model would in this example would hold any collections we may have, as well as store any attributes that our application view may want to respond to:
&lt;br&gt;
&lt;br&gt;
var MovieAppModel = Backbone.Model.extend({
initialize: function () {
// init and store our MovieCollection in our app object
this.movies = new MovieCollection();
}
});&lt;/p&gt;
&lt;p&gt;Our application view would look something like this:
&lt;br&gt;
&lt;br&gt;
var MovieAppView = Backbone.View.extend({
initialize: function () {
// this.model refers the the model we pass to the view when we
// first init our view. So here we listen for changes to the movie collection.
this.model.movies.bind(&apos;add&apos;, this.addMovie);
this.model.movies.bind(&apos;remove&apos;, this.removeMovie);
},
&lt;br&gt;
events: {
// any user events (clicks etc) we want to respond to
},
&lt;br&gt;
// grab and populate our main template
render: function () {
// once again this is using ICanHaz.js, but you can use whatever
this.el = ich.app(this.model.toJSON());
&lt;br&gt;
// store a reference to our movie list
this.movieList = this.$(&apos;#movieList&apos;);
&lt;br&gt;
return this;
},
&lt;br&gt;
addMovie: function (movie) {
var view = new MovieView({model: movie});
&lt;br&gt;
// here we use our stored reference to the movie list element and
// append our rendered movie view.
this.movieList.append(view.render().el);
},
&lt;br&gt;
removeMovie: function (movie) {
// here we can use the html ID we stored to easily find
// and remove the correct element/elements from the view if the
// collection tells us it&apos;s been removed.
this.$(&apos;#&apos; + movie.get(&apos;htmlId&apos;)).remove();
}
});&lt;/p&gt;
&lt;p&gt;Ok so now for a snapshot of the entire app. I&apos;ve included all my dependencies, each in their own file (read notes on this below). We also include the ICanHaz.js templates. Then on &lt;code class=&quot;language-text&quot;&gt;$(document).ready()&lt;/code&gt; I would simply call the init function and pass in whatever variables the server-side code may have written to my template. Then we draw our app view by calling its &lt;code class=&quot;language-text&quot;&gt;render()&lt;/code&gt; method and appending that to our &lt;code class=&quot;language-text&quot;&gt;&amp;lt;body&amp;gt;&lt;/code&gt; element like so:
&lt;br&gt;
&lt;br&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Movies App&lt;/title&gt;
&lt;br&gt;
&lt;!-- libs --&gt;
&lt;script src=&quot;jquery.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;underscore.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;backbone.js&quot;&gt;&lt;/script&gt;
&lt;br&gt;
&lt;!-- client templating --&gt;
&lt;script src=&quot;mustache.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;ICanHaz.js&quot;&gt;&lt;/script&gt;
&lt;br&gt;
&lt;!-- your app --&gt;
&lt;script src=&quot;Movie.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;MovieCollection.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;MovieView.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;MovieAppModel.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;MovieAppView.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;MovieAppController.js&quot;&gt;&lt;/script&gt;
&lt;br&gt;
&lt;!-- ICanHaz templates --&gt;
&lt;script id=&quot;app&quot; type=&quot;text/html&quot;&gt;
&lt;h1&gt;Movie App&lt;/h1&gt;
&lt;ul id=&quot;movies&quot;&gt;&lt;/ul&gt;
&lt;/script&gt;
&lt;br&gt;
&lt;script id=&quot;movie&quot; type=&quot;text/html&quot;&gt;
&lt;li id=&quot;{{ htmlId }}&quot;&gt;&lt;span class=&quot;title&quot;&gt;{{ title }}&lt;/span&gt; &lt;span&gt;{{ format }}&lt;/span&gt;&lt;/li&gt;
&lt;/script&gt;
&lt;br&gt;
&lt;script&gt;&lt;br&gt;
$(document).ready(function () {
// init our app
window.app = MovieAppController.init({
account: &apos;{{ user.get_profile.account.slug }}&apos;,
// etc, etc
});
&lt;br&gt;
// draw our main view
$(&apos;body&apos;).append(app.view.render().el);
});&lt;br&gt;
&lt;/script&gt;
&lt;br&gt;
&lt;/head&gt;
&lt;body&gt;&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;All said and done, now if we add or remove any movies from our collection or change their titles in the model those changes will just be reflected in the HTML like magic. With all the proper behaviors you&apos;d defined for them in your MovieView. &lt;/p&gt;
&lt;h3 id=&quot;general-tips&quot;&gt;&lt;a href=&quot;#general-tips&quot; aria-label=&quot;general tips permalink&quot; class=&quot;anchor&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;General Tips&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Store all your objects in their own files for development.&lt;/li&gt;
&lt;li&gt;Compress and minify all your JS into one file for production.&lt;/li&gt;
&lt;li&gt;Use JSLint&lt;/li&gt;
&lt;li&gt;Extend underscore.js for any of your global utility type functions instead of modifying native objects. More on that &lt;a href=&quot;http://gist.github.com/641397&quot;&gt;in this gist&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;jQuery should only be used in your views. That way you can potentially unit test your model and collections on the server side.&lt;/li&gt;
&lt;li&gt;Use generic jQuery events to signal other views in your app. That way you don&apos;t tightly couple them.&lt;/li&gt;
&lt;li&gt;Keep your models as simple as possible.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I know I&apos;ve covered a lot of stuff here, and some of it duplicates what&apos;s available in the &lt;a href=&quot;http://documentcloud.github.com/backbone/&quot;&gt;backbone.js documentation&lt;/a&gt; but when I started working on building an app with it, I would have wanted a complete, yet somewhat high-level walkthrough like this. So I figured I&apos;d write one. Big props to DocumentCloud and &lt;a href=&quot;http://github.com/jashkenas&quot;&gt;Jeremy Ashkenas&lt;/a&gt; for creating and sharing backbone with us.&lt;/p&gt;
&lt;p&gt;If you have any thoughts, comments or reactions I&apos;m &lt;a href=&quot;http://twitter.com/HenrikJoreteg&quot;&gt;@HenrikJoreteg&lt;/a&gt; on twitter. Thanks and good luck.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;If you&apos;re building a single page app, keep in mind that &amp;#x26;yet offers consulting, training and development services. Hit us up (&lt;a href=&quot;mailto:henrik@andyet.net&quot;&gt;henrik@andyet.net&lt;/a&gt;) and tell us what we can do to help.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Welcome the Vander Wilt!]]></title><description><![CDATA[Nate Vander Wilt is the diversely talented web and desktop developer who makes the sixth employee added to &yet over the last year. We got…]]></description><link>https://blog.andyet.com/2010/06/28/welcome-the-vander-wilt/</link><guid isPermaLink="false">https://blog.andyet.com/2010/06/28/welcome-the-vander-wilt/</guid><pubDate>Mon, 28 Jun 2010 16:39:25 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2dc8ed4210756ce89c6f73f3a38ac386/b701e/nate.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 63.57615894039734%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAEEAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAACA//aAAwDAQACEAMQAAABTj1lWk5Ih//EABsQAAICAwEAAAAAAAAAAAAAAAECAAMREhMi/9oACAEBAAEFArADMqFF3OOfCneOx6f/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFX/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHhAAAgIABwAAAAAAAAAAAAAAAAECERASITFRYfD/2gAIAQEABj8C1HS7MvlhGT3JXyf/xAAaEAACAwEBAAAAAAAAAAAAAAABEQAhQWGh/9oACAEBAAE/ITugUYmEAVOy2z1HxCklShwxL7kuBlrn/9oADAMBAAIAAwAAABDHL//EABcRAQEBAQAAAAAAAAAAAAAAAAEAESH/2gAIAQMBAT8QEOMnb//EABcRAQEBAQAAAAAAAAAAAAAAAAEAESH/2gAIAQIBAT8QTewN/8QAHBABAQACAwEBAAAAAAAAAAAAAREAITFBUaHx/9oACAEBAAE/EG8j42weZiShGmMP59wjQrW1T67mO9BCbuPAx2aY7J7xjESQrl3n/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;nate&quot;
        title=&quot;&quot;
        src=&quot;/static/2dc8ed4210756ce89c6f73f3a38ac386/3cb18/nate.jpg&quot;
        srcset=&quot;/static/2dc8ed4210756ce89c6f73f3a38ac386/0a254/nate.jpg 151w,
/static/2dc8ed4210756ce89c6f73f3a38ac386/c8fe0/nate.jpg 303w,
/static/2dc8ed4210756ce89c6f73f3a38ac386/3cb18/nate.jpg 605w,
/static/2dc8ed4210756ce89c6f73f3a38ac386/39048/nate.jpg 908w,
/static/2dc8ed4210756ce89c6f73f3a38ac386/b701e/nate.jpg 934w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nate Vander Wilt is the diversely talented web and desktop developer who makes the sixth employee added to &amp;#x26;yet over the last year. We got to know Nate primarily on Twitter, believe it or not.&lt;/p&gt;
&lt;p&gt;Nate&apos;s a midwest transplant currently living on a semi-dusty gravel road in the bustling city of Outlook, WA. &lt;/p&gt;
&lt;p&gt;Nate brings to the team his diverse talents in &quot;cloud cartography&quot; (geography and web mapping), multitouch interface, Mac, iPhone, and HTML5 web application development. &lt;/p&gt;
&lt;p&gt;Before joining &amp;#x26;yet, Nate ran Mac and iPhone software company &lt;a href=&quot;http://calftrail.com/&quot;&gt;Calf Trail&lt;/a&gt; and worked as a contractor, developing custom web mapping solutions for clients like the National Weather Service. &lt;/p&gt;
&lt;p&gt;Here&apos;s Nate&apos;s thoughts, from his cleverly titled post, &lt;a href=&quot;http://www.extinguishedscholar.com/wpglob/?p=702&quot;&gt;HTML 5.0 Transitional&lt;/a&gt;: &lt;/p&gt;
&lt;p&gt;Today I officially accepted a full-time job as “Web Application Developer and GIS &lt;strike&gt;Expert&lt;/strike&gt;Journeyman” — employee number seven — at &amp;#x26;yet.&lt;/p&gt;
&lt;p&gt;Since meeting &amp;#x26;yet (when it was just Adam Brault) a little over a year ago, it’s moved in my regard from “cool local website company” to “top-notch team” to “dream employer”. &lt;/p&gt;
&lt;p&gt;To be honest, though, the job offer was mostly unexpected and I’m still adjusting to the task of becoming “dream employee” instead of an independent contractor. Writing shareware for &lt;a href=&quot;http://calftrail.com/&quot;&gt;Calf Trail&lt;/a&gt; was a chance to explore all my ideals. Especially the one about money not being important. &lt;/p&gt;
&lt;p&gt;Working with &amp;#x26;yet is about combining diverse talents and perspectives into one team that shares responsibility for breadwinning — and fantasticmaking, of course. &lt;/p&gt;
&lt;p&gt;I’m deeply grateful that I’ve been led to and then given this opportunity. While desktop software still interests me as a hobby, times were shifting and I’d &lt;a href=&quot;http://www.extinguishedscholar.com/wpglob/?p=615&quot;&gt;already chosen the open web&lt;/a&gt; over giving 30% ownership of my livelihood to a corporation who squish liberty like bug. Joining &amp;#x26;yet mostly means a much greater chance of success in this next stage of life. &lt;/p&gt;
&lt;p&gt;We’re still working out the details, but the basic gist is that I will be moving all my paid geo, web and technical writing services to &amp;#x26;yet. Calf Trail will remain, for the time being anyway, but mostly as a home for some desktop and photo management experiments. (More about that later, and I’ll be posting the official “Calf Trail” plan on the company blog when Calf Trail has an official plan.) &lt;/p&gt;
&lt;p&gt;So, yeah…uh…that’s today’s nerdishness news. DRAMATIC CLOSE. &lt;/p&gt;
&lt;p&gt;P.S. Nate isn&apos;t the only person that &amp;#x26;yet hired because of Twitter... &lt;/p&gt;
&lt;p&gt;Henrik has a really nice recounting of his hiring process up on his blog. (We added Henrik Joreteg to the team in February after recruiting him out of Southern California.) &lt;/p&gt;
&lt;p&gt;It&apos;s especially hilarious that he nearly unfollowed Adam for being too random. &lt;/p&gt;
&lt;p&gt;He wouldn&apos;t have been the first. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[New digs]]></title><description><![CDATA[We've moved! Our old location was great, but since our staff size is multiplying like a family of rabbits, we had completely out grown it in…]]></description><link>https://blog.andyet.com/2010/06/28/new-digs/</link><guid isPermaLink="false">https://blog.andyet.com/2010/06/28/new-digs/</guid><pubDate>Mon, 28 Jun 2010 16:26:49 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0fc9fd517653d25cd76e8fa1ef2cf6c4/b701e/party.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 605px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 63.57615894039734%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIEAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAACAf/aAAwDAQACEAMQAAABj0VDe6RBX//EABsQAAICAwEAAAAAAAAAAAAAAAECAwQAERIj/9oACAEBAAEFAhX0kaqrRv0DITXQnK58v//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ASf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPwFn/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAECERBRYaH/2gAIAQEABj8Ct0RkX08Gtxx//8QAHBAAAgMAAwEAAAAAAAAAAAAAAREAITFBUYGh/9oACAEBAAE/IdtE/IyYd+VGbDQCgBSPKDB+lyquzP/aAAwDAQACAAMAAAAQ/P8A/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARMf/aAAgBAwEBPxBHbC//xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQIBAT8Q0Frf/8QAHBABAAMAAwEBAAAAAAAAAAAAAQARITFBYXGB/9oACAEBAAE/ELVjRFa/b7B4unPT1AtAEOwOQzLOi7YWMOGGqLSqc+xulk+t8z//2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;office warming party&quot;
        title=&quot;&quot;
        src=&quot;/static/0fc9fd517653d25cd76e8fa1ef2cf6c4/3cb18/party.jpg&quot;
        srcset=&quot;/static/0fc9fd517653d25cd76e8fa1ef2cf6c4/0a254/party.jpg 151w,
/static/0fc9fd517653d25cd76e8fa1ef2cf6c4/c8fe0/party.jpg 303w,
/static/0fc9fd517653d25cd76e8fa1ef2cf6c4/3cb18/party.jpg 605w,
/static/0fc9fd517653d25cd76e8fa1ef2cf6c4/39048/party.jpg 908w,
/static/0fc9fd517653d25cd76e8fa1ef2cf6c4/b701e/party.jpg 934w&quot;
        sizes=&quot;(max-width: 605px) 100vw, 605px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&apos;ve moved! Our old location was great, but since our staff size is multiplying like a family of rabbits, we had completely out grown it in less than a year. So we decided to trade in our crowed workspace for a custom designed upgrade down the street.&lt;/p&gt;
&lt;p&gt;Our new space is at 140 Gage Boulevard in Richland. We&apos;ve each got our own offices, conference room, kitchenette and a swanky brainstorming space. With a creative color scheme, custom art and leather sofas, it&apos;s a downright gorgeous workspace. &lt;/p&gt;
&lt;p&gt;On April 8th we had an Open House party with our friends and neighbors, nGenuity and elevate. We had great food, live music and a couple hundred awesome people stop by to show their support. &lt;/p&gt;
&lt;p&gt;I think all of our team members feel lucky that we get to call this place home. We hope you are as excited as we are to see what we can accomplish in our awesome new space! &lt;/p&gt;
&lt;p&gt;Photo by Jenifer Zohn Photography. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[And here we go...]]></title><description><![CDATA[As a web design and development company, it's incredibly hard to build things for yourself.This site has been in process since early August…]]></description><link>https://blog.andyet.com/2009/12/15/here-we-go/</link><guid isPermaLink="false">https://blog.andyet.com/2009/12/15/here-we-go/</guid><pubDate>Tue, 15 Dec 2009 18:08:18 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8e98cc61ebc8716513c7f4cd80461d86/7cc5e/comic.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 480px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 74.8344370860927%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCAwX/xAAWAQEBAQAAAAAAAAAAAAAAAAAEAQP/2gAMAwEAAhADEAAAAblHsZGYREX/xAAaEAACAgMAAAAAAAAAAAAAAAABEgACAxMi/9oACAEBAAEFAtHWda2jES5DMJ//xAAaEQEAAgMBAAAAAAAAAAAAAAABAAIDBBEh/9oACAEDAQE/AdatLr2OBHyf/8QAGBEAAwEBAAAAAAAAAAAAAAAAAAECA0H/2gAIAQIBAT8BqrXRbSf/xAAaEAACAgMAAAAAAAAAAAAAAAABEAACERJh/9oACAEBAAY/AuTWoZyv/8QAGxAAAwEAAwEAAAAAAAAAAAAAAAERITFhcZH/2gAIAQEAAT8haK3OqNDe0hFF9NQ3hobNw//aAAwDAQACAAMAAAAQ2O//xAAcEQABAwUAAAAAAAAAAAAAAAABACFBMYGhwdH/2gAIAQMBAT8QgiIJzFNo0Dhbq//EABgRAQADAQAAAAAAAAAAAAAAAAEAEbHR/9oACAECAQE/EKVhRa7yf//EAB4QAQEAAgEFAQAAAAAAAAAAAAERACExUWFxgcHh/9oACAEBAAE/EIOaYhMnUuFNOL6y3eU4C+TgzfbT5/e9yGCE6T5n/9k=&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;an ampersand&quot;
        title=&quot;&quot;
        src=&quot;/static/8e98cc61ebc8716513c7f4cd80461d86/7cc5e/comic.jpg&quot;
        srcset=&quot;/static/8e98cc61ebc8716513c7f4cd80461d86/0a254/comic.jpg 151w,
/static/8e98cc61ebc8716513c7f4cd80461d86/c8fe0/comic.jpg 303w,
/static/8e98cc61ebc8716513c7f4cd80461d86/7cc5e/comic.jpg 480w&quot;
        sizes=&quot;(max-width: 480px) 100vw, 480px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As a web design and development company, it&apos;s incredibly hard to build things for yourself.&lt;/p&gt;
&lt;p&gt;This site has been in process since early August, 2009, when we as a team sat down and discussed our vision for where we wanted to go. &lt;/p&gt;
&lt;p&gt;We put together a general outline and a plan for how we wanted to approach things. Then &lt;a href=&quot;/team/amy/&quot;&gt;Amy&lt;/a&gt; rolled up her sleeves and took a crack at a conceptual design based on an idea from one of her Red Room posters. &lt;/p&gt;
&lt;p&gt;The plan has changed numerous times since then, as has the content and design. We&apos;ve discussed and debated, wrestled and wrangled, but we&apos;re ultimately grateful to have had the time to pick things apart and really think long and deep about what we wanted to present as a team. &lt;/p&gt;
&lt;p&gt;In the end, we&apos;re excited that what we do is finally presented in a way that reflects the unique team that has come together at &amp;#x26;yet. It feels that this site was another missing piece of the puzzle we&apos;ve been assembling for the last two years. &lt;/p&gt;
&lt;p&gt;Thank you very much to the following folks who helped us out on the project: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.melanibrown.com/&quot;&gt;Melani Brown&lt;/a&gt; (photography)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The SagePort Grille in Richland (photo shoot location)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://twitter.com/adam_baldwin&quot;&gt;Adam Baldwin&lt;/a&gt; of &lt;a href=&quot;http://ngenuity-is.com&quot;&gt;nGenuity&lt;/a&gt; (security, etc.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://joreteg.com&quot;&gt;Henrik Joreteg&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So here we go. &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Thank you!]]></title><description><![CDATA[We’re humbled by the support of so many who have helped us grow from one to four (plus extended team) in just a year and a half.We have some…]]></description><link>https://blog.andyet.com/2009/12/15/thank-you/</link><guid isPermaLink="false">https://blog.andyet.com/2009/12/15/thank-you/</guid><pubDate>Tue, 15 Dec 2009 18:06:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1efe2e75b0de0b5870abae623e95a4a2/7cc5e/team_thankyou.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-wrapper&quot;
    style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 480px;&quot;
  &gt;
    &lt;span
      class=&quot;gatsby-resp-image-background-image&quot;
      style=&quot;padding-bottom: 58.94039735099338%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABhs5rB0LKP//EABsQAQACAgMAAAAAAAAAAAAAAAIBAwARBBIh/9oACAEBAAEFAgEaxyJOXTtlz1K8Vk7/AP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABsQAQACAgMAAAAAAAAAAAAAAAEAERAhEhMx/9oACAEBAAY/Aux8nESiXEvUdGP/xAAaEAEAAwEBAQAAAAAAAAAAAAABACFBEWEx/9oACAEBAAE/IQAr2bkvKoIvdal5LtNKiGp55E/U/9oADAMBAAIAAwAAABBYL//EABYRAQEBAAAAAAAAAAAAAAAAABEAIf/aAAgBAwEBPxBwm//EABcRAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQIBAT8Qglh//8QAGxABAQACAwEAAAAAAAAAAAAAAREAMSFBYVH/2gAIAQEAAT8QbiibBRBu9uAcKESKrJB8W+mIt+L6r1lIgUlRj8yK8LvXxnJRoM//2Q==&apos;); background-size: cover; display: block;&quot;
    &gt;&lt;/span&gt;
    &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;box-shadow:inset 0px 0px 0px 400px white;&quot;
        alt=&quot;thank you&quot;
        title=&quot;&quot;
        src=&quot;/static/1efe2e75b0de0b5870abae623e95a4a2/7cc5e/team_thankyou.jpg&quot;
        srcset=&quot;/static/1efe2e75b0de0b5870abae623e95a4a2/0a254/team_thankyou.jpg 151w,
/static/1efe2e75b0de0b5870abae623e95a4a2/c8fe0/team_thankyou.jpg 303w,
/static/1efe2e75b0de0b5870abae623e95a4a2/7cc5e/team_thankyou.jpg 480w&quot;
        sizes=&quot;(max-width: 480px) 100vw, 480px&quot;
      /&gt;
  &lt;/span&gt;
  &lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We’re humbled by the support of so many who have helped us grow from one to four (plus extended team) in just a year and a half.&lt;/p&gt;
&lt;p&gt;We have some exciting things on their way soon, including an all-new realtime web product. We&apos;re thrilled to be able to launch the new site so we can get back to the business of business! &lt;/p&gt;
&lt;p&gt;It&apos;s a privilege to be able to serve the great customers we&apos;ve been able to work with so far and it&apos;s a joy to be a part of the great Tri-Cities area tech community. &lt;/p&gt;
&lt;p&gt;So—thank you! &lt;/p&gt;
&lt;p&gt;With love, &lt;/p&gt;
&lt;p&gt;the &amp;#x26;yet Team (&lt;a href=&quot;/team/nathan/&quot;&gt;Nathan&lt;/a&gt; / &lt;a href=&quot;/team/angela/&quot;&gt;Angela&lt;/a&gt; / &lt;a href=&quot;/team/amy/&quot;&gt;Amy&lt;/a&gt; / &lt;a href=&quot;/team/adam/&quot;&gt;Adam&lt;/a&gt;) &lt;/p&gt;</content:encoded></item></channel></rss>