<?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[Jon Phenow]]></title><description><![CDATA[Jon Phenow's blog]]></description><link>https://jphenow.com/blog</link><generator>GatsbyJS</generator><lastBuildDate>Tue, 20 Jan 2026 17:48:27 GMT</lastBuildDate><item><title><![CDATA[My FeeLLMs]]></title><description><![CDATA[I've remained largely quiet about the surge of LLMs in software engineering, apps, and the broader world.
I've held back because I think I…]]></description><link>https://jphenow.com/blog/2025/04/my-feellms/</link><guid isPermaLink="false">https://jphenow.com/blog/2025/04/my-feellms/</guid><pubDate>Mon, 14 Apr 2025 20:10:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve remained largely quiet about the surge of LLMs in software engineering, apps, and the broader world.
I’ve held back because I think I have largely repetitive quandaries, qualms, and quips.
For whatever reason, I’ve decided now is the time to write about it.&lt;/p&gt;&lt;p&gt;This post is largely a ping pong between my anxieties about LLMs and my conflicting feelings of anxious optimism.&lt;/p&gt;&lt;p&gt;I’m worried about the work that was stolen to make LLMs go.
Unfortunately, it seems unlikely we’ll be returning Pandora to her box.
I don’t think that means we should give up on doing better to upgrade our understanding of licensing works that wind up in LLMs.
As much as possible, I prefer to avoid supporting folks that do things like read the entire internet regardless of licensing then complain when they believe someone… &lt;a href=&quot;https://www.nbcnews.com/tech/tech-news/openai-says-deepseek-may-inapproriately-used-data-rcna189872&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;stole&lt;/a&gt; “their” IP.
While LLM companies made magnificent leaps forward, I’m not convinced they had to ~steal from people to make such progress.&lt;/p&gt;&lt;p&gt;I’m excited by the forced progress on things like energy production, though I don’t feel much hope over our ability to either burn less or sufficiently convert the majority of our burning to renewables.
Something about a guy named &lt;a href=&quot;https://en.wikipedia.org/wiki/Jevons_paradox&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Jevon&lt;/a&gt;.
So far the most I feel I can say about this is that it’s just a discomfort like that tag in my shirt I can’t find that’s scratching my skin.
I suspect the longer term effects are greater than any of us can conceive yet.
In reality some of the energy side-effects are likely already here but don’t affect my day-to-day grievances.&lt;/p&gt;&lt;p&gt;I listen to the Center for Humane Technology’s &lt;a href=&quot;https://www.humanetech.com/podcast/the-man-who-predicted-the-downfall-of-thinking&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;podcast&lt;/a&gt;, and they’ve been circling on an insidious concern around LLMs that has stuck with me: the unknowns around what this will do to us and our brains.
While I’m concerned about the potential for lost jobs and a world unprepared to deal with it, I’m perhaps more concerned for the accidental reliance on it for things like critical thinking, research.
I try my best to hit [tab] on &lt;a href=&quot;https://www.cursor.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Cursor&lt;/a&gt; when it’s things I believe to be skippable - things that are not my primary focus that could just be done, and are simple enough.
But much like the algorithmic feeds, it’s hard to fully grasp what this will do to society and how we exist in a world where many people are already dubious of our ability to think critically.
I offer no answers, only anxieties.
It could just be a mild discomfort I have now, or it could slowly destroy us inside.
It’s also the kind of thing that’s hard to fend off as any single individual.&lt;/p&gt;&lt;p&gt;Frustratingly, I find it immensely useful to let it do some of the things ([tab] on Cursor) that increasingly feel below what I &lt;strong&gt;could&lt;/strong&gt; be focusing on.
I get a little bit of a boost when I feel like it worked or got me 95% of the way without making me work as hard as I would have without it.
It remains to be seen whether my feeling is the emotional response to getting the robots to do something for me or whether it actually allowed me to do something faster then put more focus elsewhere.
I suspect it’s a little of both.&lt;/p&gt;&lt;p&gt;For whatever reason, this also feels like a moment to pontificate about what might be missing from LLM tools for software engineers.
I see roughly 3 very broad angles that LLMs can help with in software engineering practices: new projects, existing projects, and operating a project.&lt;/p&gt;&lt;p&gt;A lot of the tools out there are good and seem focused on “new projects” (Lovable, Replit, Bolt.new, v0 [Vercel]) but I’ve had issues mostly with ongoing conversation, token limits, winding up in a back-and-forth with the LLM to get something right.&lt;/p&gt;&lt;p&gt;There are good tools out there for “existing code” (Cursor, Co-Pilot).
As an experienced engineer, I find these the most useful.
I have a project, I understand it, I want to point the LLM around to do things or just provide a snappy autocomplete to the work I already understand well.&lt;/p&gt;&lt;p&gt;The third angle: “I have code, I need something to make it run somewhere, stay running, etc.” is one I haven’t seen much of yet.
There are probably lot of good reasons for that.
My guess is that it’s harder to do well enough that we’re willing to let something go accidentally run our cloud bill or do something with less human oversight.
The first two tools generally have a place for a human to interact.
I’m not sure this third does or the interaction moments are very different from the first two.&lt;/p&gt;&lt;p&gt;I think something roughly groundbreaking Could be finding a way to get the third thing running, then finding a way to tie together these three things into one “build, iterate, and run software.”
Then again, I’d like to have a job in 5 years so forget what I said, definitely don’t use LLMs for software.&lt;/p&gt;&lt;p&gt;In all seriousness though, I’ve found some use for LLMs in my day-job and side-projects.
And while I try to keep up with an annoyingly fast-paced profession, I’ve found I do have to keep an eye on the software they’re creating.
I believe they simply aren’t ready for &lt;a href=&quot;https://bsky.app/profile/janelleshane.com/post/3lmnpkz53vc2e&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;unattended&lt;/a&gt; software building yet, and I suspect they won’t be until we can find more annoying ways to put the right context in front of them.&lt;/p&gt;&lt;p&gt;P.S. This post is a bit stream-of-consciousness and fails to go as deep as I’d like on anything in particular.
I hope I’ll find some time to bring some more depth to each of these points as I get back into the habit of writing.&lt;/p&gt;&lt;p&gt;What are you most concerned about? Excited about?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[I'm back (2025)]]></title><description><![CDATA[Hello again. I'm getting back into writing. I probably won't write consistently. We'll see if I write something beyond the first few ideas I…]]></description><link>https://jphenow.com/blog/2025/04/trying-to-write-again/</link><guid isPermaLink="false">https://jphenow.com/blog/2025/04/trying-to-write-again/</guid><pubDate>Sat, 12 Apr 2025 01:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hello again.&lt;/p&gt;&lt;p&gt;I’m getting back into writing.&lt;/p&gt;&lt;p&gt;I probably won’t write consistently. We’ll see if I write something beyond the first few ideas I have.&lt;/p&gt;&lt;p&gt;I’ve always had a hard time deciding when I’ve had a thought worth writing down, and &lt;em&gt;also&lt;/em&gt; sharing.
I’ve found that it’s useful way to work through some thoughts, though.
It really helps me to get something ready to share.
It forces me to think about how I actually feel, how to present it, and whether it’s something I should rethink, research, or just let go.&lt;/p&gt;&lt;p&gt;So, I’m “back”.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Was I here before?&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;I’ll have bad insights, experiences, and once in a while I might have a thing I’m actually glad I shared.
Good luck with everything in between.&lt;/p&gt;&lt;p&gt;I doubt I said this on a blog ever so here’s a bit about me in 2025:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;I’ve been a software engineer since around 2008&lt;/li&gt;&lt;li&gt;I’m a husband (as of 2019)&lt;/li&gt;&lt;li&gt;I’m a dad (as of 2023)&lt;/li&gt;&lt;li&gt;I like building things that are useful for people&lt;/li&gt;&lt;li&gt;I have strong beliefs about how people should treat each other and how should and do systems affect that&lt;/li&gt;&lt;li&gt;I have strong beliefs about how people should treat the planet and how systems should and do affect that&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I don’t know what I’ll write about.
I’ll write about software I’m learning about, working on, or using.
I’ll probably write about life.
I’ll maybe write about things that I need to externalize in order to explore an idea out loud.
I’ll write about what I feel like writing about.&lt;/p&gt;&lt;p&gt;I’m not sure how much I love the old posts I had.
I almost removed them.
I’m going to leave them up for now.
Like tattoos, they illustrate where my head was at during different times.&lt;/p&gt;&lt;p&gt;Cheers and, if you’re reading this, welcome.&lt;/p&gt;&lt;p&gt;Be good to each other.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[When Product needs to get Technical]]></title><description><![CDATA[When Product needs to get Technical In a company with a Product team, the Product managers have one focus: Your products. Everything to do…]]></description><link>https://jphenow.com/blog/2019/06/when-product-needs-to-get-technical/</link><guid isPermaLink="false">https://jphenow.com/blog/2019/06/when-product-needs-to-get-technical/</guid><pubDate>Wed, 12 Jun 2019 15:25:41 GMT</pubDate><content:encoded>&lt;p&gt;When Product needs to get Technical&lt;/p&gt;&lt;p&gt;In a company with a Product team, the Product managers have one focus: Your products. Everything to do with what your company is producing and selling is what they deal with. That means anything from setting up your Support team to understand the functionality to cooperating with Development to build it, from sanctioning Marketing to Sales preparation and training. They’re generally managing the product from an idea perspective: what is it solving, what exactly are we building and supporting, who is the product targeting. Each of the deeper caveats like “how is it built” are a conversation between Product and the other appropriate teams, like Development. I’d like to specifically explore the Product and Development relationship.&lt;/p&gt;&lt;p&gt;Now would be a good time to step back and paint a picture of what I’ve seen so far. A few people build a company around&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Developing a Writing Plan]]></title><description><![CDATA[You  just  have to start. As in anything, your idea doesn’t mean anything until you start working with it. You can roll it around in your…]]></description><link>https://jphenow.com/blog/2019/06/developing-a-writing-plan/</link><guid isPermaLink="false">https://jphenow.com/blog/2019/06/developing-a-writing-plan/</guid><pubDate>Wed, 12 Jun 2019 15:25:40 GMT</pubDate><content:encoded>&lt;p&gt;You &lt;em&gt;just&lt;/em&gt; have to start. As in anything, your idea doesn’t mean anything until you start working with it. You can roll it around in your head all you want, thinking about all of the lovely ideas you have, but it doesn’t mean anything will its bouncing around up there. While you hold it in your head you could forget any minor epiphanies you have, you can’t share it with others to focus the argument or discover other useful directions it could take. You won’t have learned anything. A fleeting thought is as useful as that time you thought about that great idea that could fix the world then instead hid in your house, looking at Reddit. You didn’t help anyone, not even yourself, by just &lt;em&gt;thinking&lt;/em&gt; about it. &lt;/p&gt;&lt;p&gt;Let’s take writing as an example. Decide what your purpose for writing is. I’ve recently decided that I would like to write to be more timeless and widely applicable. Its not an extraordinarily fresh idea, nor is its essence something I haven’t attempted. That doesn’t matter though, I have a theme that I’m aiming at for now. That theme will most likely change over time. This way, though, while I’m putting down notes about what next to write about, I can use this as a guideline for what to focus on. What to focus on within each article or whether that article belongs &lt;em&gt;at all&lt;/em&gt;. &lt;/p&gt;&lt;p&gt;The first theme that you focus on will not be your last. Using myself as an example again, I started writing years ago. First, it was about my travels as a kid in school, mostly used while I was travelling abroad to communicate back to family and friends what I’d been up to. That died after a while (or after I inevitably had less interesting life stories to write about). I eventually returned to talk about the minute details in code that I had figured out, or understood about something fairly specific. A lot of the posts were in code. As I grew up as a Software Engineer I recognized less and less when a particular obstacle was worth penning a blog post. The writing days died again. Finally, in a most recent attempt, I was writing about the slightly more abstract concepts and critiquing them using pseudo-code examples. Again the writing died after a short period. &lt;/p&gt;&lt;p&gt;You could argue the first two themes were eventually going to die, by my own hand if not by time’s. The last theme, where I considered writing about abstract concepts using some more concrete examples, had a little more meat to it. That’s all well and good, but none of the themes are &lt;em&gt;why&lt;/em&gt; the writing died. They died because I didn’t make it a priority. &lt;/p&gt;&lt;p&gt;Ultimately to be successful at something it has to become part of your part of your week, part of your day, maybe even part of every hour. For my endeavor, I’ve decided to carve out exactly 30 minutes into my every-day schedule. That might mean puking words out into a notebook to grow an idea, talking through it with a friend and writing notes down or editing. This time is devoted to the actual &lt;em&gt;act&lt;/em&gt; of writing. Get those initial, rough ideas down is important. Speaking realistically, though, you won’t (and shouldn’t) use all that much of the words from these vomit-sessions. These bits of time are for two things: creating a habit of expressing yourself and your thoughts in words, and for finding general ideas that you feel you can talk out-loud about. &lt;/p&gt;&lt;p&gt;Forming that habit will be enough to evolve your writing, your thinking, your style. The habit of writing every day won’t, in and of itself, produce a publishable blog — if that’s what you’re into. Its a huge start, though. &lt;/p&gt;&lt;p&gt;When you’re writing and writing to write you eventually realize a few things. A lot of your initial ideas suck. A lot of the ideas that don’t suck aren’t distilled to what you really want to talk about. It doesn’t flow well into an understanding of the idea you’re trying to get across to your audience. When you write every day and make a similar habit to read back over things, pick the good one, do some editing, trimming, external research, peer review (if possible), you might actually have something. &lt;/p&gt;&lt;p&gt;Its hard. Accomplishing anything like this is hard. But if it were easy you wouldn’t learn anything, nor would your readers.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Doctor Who comments on ISIS and Domestic Mass Shootings]]></title><description><![CDATA[S09E11 @32:18]]></description><link>https://jphenow.com/blog/2019/06/doctor-who-comments-on-isis-and-domestic-mass-shootings/</link><guid isPermaLink="false">https://jphenow.com/blog/2019/06/doctor-who-comments-on-isis-and-domestic-mass-shootings/</guid><pubDate>Wed, 12 Jun 2019 15:25:40 GMT</pubDate><content:encoded>&lt;p&gt;S09E11 @32:18&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Focus is a Limited Resource]]></title><description><![CDATA[Focus is a difficult thing to achieve. Sometimes it happens by accident because you’re generally interested and driven. That interest and…]]></description><link>https://jphenow.com/blog/2019/06/focus-is-a-limited-resource/</link><guid isPermaLink="false">https://jphenow.com/blog/2019/06/focus-is-a-limited-resource/</guid><pubDate>Wed, 12 Jun 2019 15:25:40 GMT</pubDate><content:encoded>&lt;p&gt;Focus is a difficult thing to achieve. Sometimes it happens by accident because you’re generally interested and driven. That interest and drive can come because of the specific topic or task, but often times a concerted effort is required to actually focus and get a thing done. I’m here to tell you that its entirely possible to find focus regardless of interest. &lt;/p&gt;&lt;p&gt;In the past few months I started working remotely for a company. This wasn’t a big shift for me, at first. My previous company was pretty flexible, which gave it sort of a hybrid feeling of remote and in-office. The initial months of working with this new company were powered by pure excitement of working for a different company, with new people and new ideas. Luckily the most recent months and weeks are still filled with an awesome company, great people and fun, challenging ideas. Something is different though, my mood and and output changed for a brief time.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Crossing the finish line]]></title><description><![CDATA[In Software Engineering code that is running in production is infinitely more valuable than  anything  you have built that isn’t yet…]]></description><link>https://jphenow.com/blog/2019/06/crossing-the-finish-line/</link><guid isPermaLink="false">https://jphenow.com/blog/2019/06/crossing-the-finish-line/</guid><pubDate>Wed, 12 Jun 2019 15:25:40 GMT</pubDate><content:encoded>&lt;p&gt;In Software Engineering code that is running in production is infinitely more valuable than &lt;em&gt;anything&lt;/em&gt; you have built that isn’t yet deployed. That is to say you could have this amazing new twist on a feature that’s beautifully written and well tested, but it doesn’t mean anything until its been deployed to your customers. Up until its deployed its just vapor. Nothing more.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Horseshoes & Hand Grenades]]></title><description><![CDATA[“Close only matters in horseshoes and hand grenades,” I first heard from my grandpa many years ago. Many things are binary, true or false…]]></description><link>https://jphenow.com/blog/2019/06/horseshoes-and-hand-grenades/</link><guid isPermaLink="false">https://jphenow.com/blog/2019/06/horseshoes-and-hand-grenades/</guid><pubDate>Wed, 12 Jun 2019 15:25:40 GMT</pubDate><content:encoded>&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/0518a31155bd8b40100fd5f44183e6c4/eea4a/asset-1.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:74.85714285714286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDAv/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAGK0wiIn//EABkQAAMBAQEAAAAAAAAAAAAAAAABAhEDEv/aAAgBAQABBQKebsXlnnCaxPobB//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABwQAAICAgMAAAAAAAAAAAAAAAABESECQUJhcf/aAAgBAQAGPwI5elOSLXaJWFvZZ//EAB0QAQADAAEFAAAAAAAAAAAAAAEAETFRIUFhcYH/2gAIAQEAAT8h4EDahv6+AIhZeS5oEGzS4BYaK7GfR6n/2gAMAwEAAgADAAAAEDQP/8QAFREBAQAAAAAAAAAAAAAAAAAAECH/2gAIAQMBAT8Qp//EABURAQEAAAAAAAAAAAAAAAAAABAh/9oACAECAQE/EIf/xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhMUFRYYH/2gAIAQEAAT8QdsDOQCu5TBgeDrjF2RYAmbNvfYJ64zRFIjhK7i7TaAnuho+QXKLbyn//2Q==&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 1&quot; title=&quot;asset 1&quot; src=&quot;/blog/static/0518a31155bd8b40100fd5f44183e6c4/29d31/asset-1.jpg&quot; srcSet=&quot;/blog/static/0518a31155bd8b40100fd5f44183e6c4/e52aa/asset-1.jpg 175w,/blog/static/0518a31155bd8b40100fd5f44183e6c4/70ebb/asset-1.jpg 350w,/blog/static/0518a31155bd8b40100fd5f44183e6c4/29d31/asset-1.jpg 700w,/blog/static/0518a31155bd8b40100fd5f44183e6c4/9ecec/asset-1.jpg 1050w,/blog/static/0518a31155bd8b40100fd5f44183e6c4/eea4a/asset-1.jpg 1280w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;“Close only matters in horseshoes and hand grenades,” I first heard from my grandpa many years ago. Many things are binary, true or false, complete or not-complete. Almost completing a task is the same as not completing that task. There is no gray area, and stop letting yourself think there is. It seems like a pretty harsh sentiment but I think there are real lessons to learn from thinking this way.&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:600px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/97af6f2472fb777b33379e974f3867fa/b4294/asset-2.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:77.14285714285715%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEAf/EABUBAQEAAAAAAAAAAAAAAAAAAAIB/9oADAMBAAIQAxAAAAFMutKSVhv/xAAcEAACAQUBAAAAAAAAAAAAAAABAgADERITFCH/2gAIAQEAAQUC6npg5O2t4F9AIl5//8QAFhEBAQEAAAAAAAAAAAAAAAAAABEB/9oACAEDAQE/AZqP/8QAFhEBAQEAAAAAAAAAAAAAAAAAABIB/9oACAECAQE/AaxT/8QAHRAAAAUFAAAAAAAAAAAAAAAAAAECECEiMTJBgf/aAAgBAQAGPwI0oLoq2LNlDf/EABsQAAIDAAMAAAAAAAAAAAAAAAERACExQXGR/9oACAEBAAE/IVat1qMiC0wKcNBBLiGJN+yuHRGIF5U//9oADAMBAAIAAwAAABBgL//EABYRAQEBAAAAAAAAAAAAAAAAAABRAf/aAAgBAwEBPxCTKf/EABcRAAMBAAAAAAAAAAAAAAAAAAABQVH/2gAIAQIBAT8Qgx4P/8QAGxABAQEBAQADAAAAAAAAAAAAAREhADFRYdH/2gAIAQEAAT8Qpacr4n1889KzTR6mebyCgFRHOdHraD86ygTUcUixEe//2Q==&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 2&quot; title=&quot;asset 2&quot; src=&quot;/blog/static/97af6f2472fb777b33379e974f3867fa/b4294/asset-2.jpg&quot; srcSet=&quot;/blog/static/97af6f2472fb777b33379e974f3867fa/e52aa/asset-2.jpg 175w,/blog/static/97af6f2472fb777b33379e974f3867fa/70ebb/asset-2.jpg 350w,/blog/static/97af6f2472fb777b33379e974f3867fa/b4294/asset-2.jpg 600w&quot; sizes=&quot;(max-width: 600px) 100vw, 600px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;Analogy time: think about completing things in terms of a marathon. In a marathon you run 26.3 miles. There’s a start line and an finish line. If I run 12 miles, and my legs give out, I did not run a marathon; I ran 12 miles and failed. If I run those same 12 miles, pass out, get some food and finish the marathon, then I ran a marathon. Every day I train, I’m working towards being able to run a marathon. That progress is all moot if I never run the marathon. Each mile during a marathon, every minute put towards that race is only progress if I complete it.&lt;/p&gt;&lt;p&gt;This applies to software projects as well. Working on code for hours then never committing your code is not progress. It might be fun for your brain or it might help you find new solutions, but that’s not necessarily progress towards your ultimate goal. Opening a pull request isn’t progress. If the pull request results in a discussion that ultimately results in a definitive answer, it could be considered progress. Opening pull requests without ever making a decision about them is like constantly training for a marathon you never intend to run.&lt;/p&gt;&lt;p&gt;There’s a few ways to train yourself to efficiently work towards your goals. (what is this? talk in the intro about what exactly we are getting at, why progress is important)&lt;/p&gt;&lt;h4 id=&quot;work-on-tangible-things&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#work-on-tangible-things&quot; aria-label=&quot;work on tangible things permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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 on tangible things&lt;/h4&gt;&lt;p&gt;You should be able to quickly grok your goal and know exactly what it is with all its caveats. Something like “I will be able to run a marathon in under 4 hours” is great, but not “train for a race.” What race? How far is the race? Am I running? Biking? The definition of what you’re working towards is one of the most important things; it defines your progress, failure, everything.&lt;/p&gt;&lt;h4 id=&quot;have-a-timeline&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#have-a-timeline&quot; aria-label=&quot;have a timeline permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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 a timeline&lt;/h4&gt;&lt;p&gt;Goals can’t go on forever. The timeline is there to help you push yourself a bit, evaluate if you’ve succeeded or not and adjust your future goals. Without a timeline you’re just lying to yourself about what you’re “focusing” on.&lt;/p&gt;&lt;h4 id=&quot;be-realistic&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#be-realistic&quot; aria-label=&quot;be realistic permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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 realistic&lt;/h4&gt;&lt;p&gt;In order to be realistic I try to find a baseline goal to understand the status quo like “run 10 miles this week.” Knowing that I can do that, stretch a bit and plan to run 13 miles next week. Understanding the baseline allowed me to decide if I should push on further or if I should keep trying to be successful at 10 miles.&lt;/p&gt;&lt;h4 id=&quot;evaluate&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#evaluate&quot; aria-label=&quot;evaluate permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Evaluate&lt;/h4&gt;&lt;p&gt;Use the basic guidelines you setup for your goal to measure whether or not you’re successful, or heading towards success. Once a goal is set I like leave it there until the end-date to keep progressing towards it, but if you evaluate and you’re clearly going to fail, maybe re-evaluate your goals and priorities then and there.&lt;/p&gt;&lt;h4 id=&quot;failure-is-ok-but-move-on&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#failure-is-ok-but-move-on&quot; aria-label=&quot;failure is ok but move on permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Failure is ok, but move on&lt;/h4&gt;&lt;p&gt;Admit failure when it happens, doing so allows you to move on and try again, maybe being more realistic. Its not the end of the world, but clearly something needs to change to be successful next time.&lt;/p&gt;&lt;p&gt;People have been saying a lot of these things for years now. I remember hearing some of this in High School and thinking it sounded silly to even talk out-loud about, because “duh.” For me, though, I thought a lot of it was obvious when someone said it, but once I actually applied some of this to how I think about work and personal goals I felt the difference. At least now I’m starting to get a clearer understanding of my abilities and can make smarter decisions about my personal priorities in life.&lt;/p&gt;&lt;hr/&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;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/97af6f2472fb777b33379e974f3867fa/b4294/asset-3.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:77.14285714285715%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEAf/EABUBAQEAAAAAAAAAAAAAAAAAAAIB/9oADAMBAAIQAxAAAAFMutKSVhv/xAAcEAACAQUBAAAAAAAAAAAAAAABAgADERITFCH/2gAIAQEAAQUC6npg5O2t4F9AIl5//8QAFhEBAQEAAAAAAAAAAAAAAAAAABEB/9oACAEDAQE/AZqP/8QAFhEBAQEAAAAAAAAAAAAAAAAAABIB/9oACAECAQE/AaxT/8QAHRAAAAUFAAAAAAAAAAAAAAAAAAECECEiMTJBgf/aAAgBAQAGPwI0oLoq2LNlDf/EABsQAAIDAAMAAAAAAAAAAAAAAAERACExQXGR/9oACAEBAAE/IVat1qMiC0wKcNBBLiGJN+yuHRGIF5U//9oADAMBAAIAAwAAABBgL//EABYRAQEBAAAAAAAAAAAAAAAAAABRAf/aAAgBAwEBPxCTKf/EABcRAAMBAAAAAAAAAAAAAAAAAAABQVH/2gAIAQIBAT8Qgx4P/8QAGxABAQEBAQADAAAAAAAAAAAAAREhADFRYdH/2gAIAQEAAT8Qpacr4n1889KzTR6mebyCgFRHOdHraD86ygTUcUixEe//2Q==&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 3&quot; title=&quot;asset 3&quot; src=&quot;/blog/static/97af6f2472fb777b33379e974f3867fa/b4294/asset-3.jpg&quot; srcSet=&quot;/blog/static/97af6f2472fb777b33379e974f3867fa/e52aa/asset-3.jpg 175w,/blog/static/97af6f2472fb777b33379e974f3867fa/70ebb/asset-3.jpg 350w,/blog/static/97af6f2472fb777b33379e974f3867fa/b4294/asset-3.jpg 600w&quot; sizes=&quot;(max-width: 600px) 100vw, 600px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;EVALUATE/DELETE&lt;/p&gt;&lt;p&gt;A few years ago I decided to train for and run the Minneapolis half marathon. So I Googled half marathon training and landed on &lt;a href=&quot;http://www.halhigdon.com/training/51130/Half-Marathon-Training-Guide&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Hal Higdon’s guide&lt;/a&gt;. I lined up my calendar to finish my training on the correct day, picked up a pair of Saucony shoes for distance running and off I went. Over the following three months, I spent much of my time keeping up with the training schedule. I did pretty well, &lt;em&gt;if I do say so myself&lt;/em&gt;. On the day of the race I had a friend drop me off near the start-line just a few minutes before the gun. Standing at the start line for a longer race is really pretty energizing. It’s hard not to ponder the work you’ve put in in the last few months, and everyone else is feeling the same way. There’s a lot of excitement. A few minutes go by, then another 10, then 15. About half an hour after the race was supposed to start Team Ortho, who runs a lot of local race events, &lt;strong&gt;cancelled&lt;/strong&gt; the event due to the looming storm. This storm was apparently particularly alarming for this race due to the close proximity of the Mississippi river to the route. Well crap, months of training and a lie of a participant T-Shirt.&lt;/p&gt;&lt;p&gt;Shortly after this failure of a half-marathon, some friends convinced me to direct my training towards a &lt;em&gt;Full&lt;/em&gt; marathon. Some re-jiggering of the training schedule, find some new routes and back on track. As the training schedule became more difficult to fit into a day so did my work schedule. One thing led to another and I wound up injuring myself a few weeks before the race. I screwed myself this time. I didn’t end up running the race. Yet again, months of training and I was still not a Marathon runner. &lt;/p&gt;&lt;p&gt;There’s no such thing as an almost-marathoner. There’s just people who’ve run marathon and people who haven’t. In terms of marathon races its more or less a badge of honor to be able to say you’ve done it. You endured that work and felt the pain and excitement of that journey. There are stages to the journey you need to take though. Let’s think about this in terms of a software project: my code is finished, mark it as complete. Something’s wrong though. &lt;/p&gt;&lt;p&gt;/end with becoming a marathon runner&lt;/p&gt;</content:encoded></item><item><title><![CDATA[An Introduction to HTTP Signing]]></title><description><![CDATA[In the world of APIs, we’re exchanging data that we care about. The data may contain sensitive information or maybe you just want to trust…]]></description><link>https://jphenow.com/blog/2019/06/an-introduction-to-http-signing/</link><guid isPermaLink="false">https://jphenow.com/blog/2019/06/an-introduction-to-http-signing/</guid><pubDate>Wed, 12 Jun 2019 15:25:40 GMT</pubDate><content:encoded>&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/7e9a4e8789362b4d0552945fedcdfa07/8ec0a/asset-1.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:74.85714285714286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAwABAv/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHBXuQzx//EABoQAAEFAQAAAAAAAAAAAAAAAAMAAQISIRD/2gAIAQEAAQUCrCLCqMblUdWNz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAICAwAAAAAAAAAAAAAAAAABEBEhMTL/2gAIAQEABj8CpIt4s4YzUf/EABsQAAMBAAMBAAAAAAAAAAAAAAABESExQVFh/9oACAEBAAE/IaKCTWsXlJrOzTHL6hKol3N9Erp//9oADAMBAAIAAwAAABCsH//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/EKf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAcEAACAgIDAAAAAAAAAAAAAAABEQAhQVExYXH/2gAIAQEAAT8QJgsDKldx0Gz7AYAHka+4IgABrgiAwOytxPtP/9k=&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 1&quot; title=&quot;asset 1&quot; src=&quot;/blog/static/7e9a4e8789362b4d0552945fedcdfa07/29d31/asset-1.jpg&quot; srcSet=&quot;/blog/static/7e9a4e8789362b4d0552945fedcdfa07/e52aa/asset-1.jpg 175w,/blog/static/7e9a4e8789362b4d0552945fedcdfa07/70ebb/asset-1.jpg 350w,/blog/static/7e9a4e8789362b4d0552945fedcdfa07/29d31/asset-1.jpg 700w,/blog/static/7e9a4e8789362b4d0552945fedcdfa07/9ecec/asset-1.jpg 1050w,/blog/static/7e9a4e8789362b4d0552945fedcdfa07/d165a/asset-1.jpg 1400w,/blog/static/7e9a4e8789362b4d0552945fedcdfa07/8ec0a/asset-1.jpg 2560w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;In the world of APIs, we’re exchanging data that we care about. The data may contain sensitive information or maybe you just want to trust the data hasn’t been tampered with. Mechanisms like TLS give us some sense of security in that you’re interacting within an encrypted transport system, but perhaps you need more validation that incoming data hasn’t changed or that the client app is who they claim to be. This is especially important for things like Personally Identifiable Information or Financial data. We can get this added sense of security using a somewhat newly drafted standard called &lt;a href=&quot;https://tools.ietf.org/html/draft-cavage-http-signatures-05&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;HTTP Signatures&lt;/a&gt;. Using this standard, as its currently drafted, you can verify that data for an HTTP Request hasn’t been altered during transport and you can use this information to gain confidence in who sent the request to your server.&lt;/p&gt;&lt;p&gt;“HTTP Signatures” is currently in the draft stage of becoming an IETF standard. Forewarning that its current draft status means that it’s still subject to changes or it could not make its way to being a full standard. The concepts and general idea, though, I think are fully worth considering. Even if it weren’t to become a standard — you could apply these concepts and permit their use using your API and provide libraries for clients to use. &lt;/p&gt;&lt;p&gt;Signing your HTTP requests is important in high priority areas specifically because TLS (and SSL) have been known to have &lt;a href=&quot;http://www.webopedia.com/TERM/S/ssl_beast.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;vulnerabilities&lt;/a&gt; over the years. You should absolutely use the latest TLS when possible, because its still a good first step. If you’re concerned about the integrity of the data entering your system, though, you should always consider extra avenues with which to validate incoming data. Specifically, HTTP request signing can help you ensure that data hasn’t changed during the transport of the request from client to server. Let’s get into some specifics about the standard to better understand.&lt;/p&gt;&lt;p&gt;Request signing parameters live either within the `Signature` header or the `Authorization` header (prefixed with “Signature ”). For the purposes of this post I will refer to the `Signature` header. Within that header there are four parameters we care about:&lt;/p&gt;&lt;h4 id=&quot;keyid&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#keyid&quot; aria-label=&quot;keyid permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;keyId&lt;/h4&gt;&lt;p&gt;The `keyId` is used to identify the client connecting to our server. This would be used, in your server, to locate the credentials that will be used to sign the data. Perhaps you have a `clients` table with an identifier (matching the `keyId` that would be provided) and a set of credentials that are used to create the signature.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Example&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;keyId=“chat-app”&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&quot;algorithm&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#algorithm&quot; aria-label=&quot;algorithm permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;algorithm&lt;/h4&gt;&lt;p&gt;The `algorithm` signifies which &lt;a href=&quot;https://tools.ietf.org/html/draft-cavage-http-signatures-03#appendix-E.2&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;signing algorithm&lt;/a&gt; was used for the request. so that both server and client are on the same page as to which algorithm will be used to verify the data. A signing algorithm uses cryptographic standards to generate a digest from the data we want to ensure hasn’t been tampered with. &lt;/p&gt;&lt;p&gt;&lt;strong&gt;Example&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;algorithm=“hmac-sha256”&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&quot;headers&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#headers&quot; aria-label=&quot;headers permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;headers&lt;/h4&gt;&lt;p&gt;The `headers` parameter is optional at this point in the standard’s draft, though I personally think you should always list them. Listing them enforces that both client and server are aware of the order of headers and will protect you from issues due to unanticipated middleware, or something of that nature, rendering your request verification invalid. Each header must be lower-cased and separated by a single space. A special identifier “(request-target)” is generated by concatenating the lowercased Method, a space and the path pseudo-headers (for more on this see Section &lt;a href=&quot;https://tools.ietf.org/html/draft-cavage-http-signatures-05#section-2.3&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;2.3.1&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: assuming we wanted the route information and the date header verified:&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;headers=“(request-target) date”&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&quot;signature&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#signature&quot; aria-label=&quot;signature permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;signature&lt;/h4&gt;&lt;p&gt;The `signature` parameter contains the actual message digest; the message digest being the encrypted data that we will validate on the server as having not been tampered with. The signature body (the not-yet-encrypted data) is created by collecting the key and value of the `headers` specified and joining them, in the order specified, with newlines. Here’s some pseudo-code to illustrate what happens to get the digest from the body:&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;algorithmFunction = getAlgorithm(algorithm, getCredentials(keyId))
base64(algorithmFunction(signatureBody))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That is to say that we must get an encryption function (using our algorithm parameter), use our credentials from the Key ID to encrypt that data, then Base 64 encode that digest.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: If we were to use the &lt;a href=&quot;http://ATp0r26dbMIxOopqw0OfABDT7CKMIoENumuruOtarj8n/97Q3htH%20%20%20%20FYpH8yOSQk3Z5zh8UxUym6FYTb5+A0Nz3NRsXJibnYi7brE/4tx5But9kkFGzG+%20%20%20%20xpUmimN4c3TMN7OFH//+r8hBf7BT9/GmHDUVZT2JzWGLZES2xDOUuMtA=&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;RSA keys provided from the draft’s test samples&lt;/a&gt;, specify `headers=“(request-target) date”`, with a request:&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;POST /foo?param=value&amp;amp;pet=dog HTTP/1.1
Host: example.com
Date: Thu, 05 Jan 2014 21:31:40 GMT
Content-Type: application/json
Digest: SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
Content-Length: 18&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Our `signature` parameter 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;signature=“KcLSABBj/m3v2DhxiCKJmzYJvnx74tDO1SaURD8Dr8XpugN5wpy8iBVJtpkHUIp4qBYpzx2QvD16t8X0BUMiKc53Age+baQFWwb2iYYJzvuUL+krrl/Q7H6fPBADBsHqEZ7IE8rR0Ys3lb7J5A6VB9J/4yVTRiBcxTypW/mpr5w=”&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ultimately, a Signature header would look 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;Signature: keyId=“chat-app”,algorithm=“hmac-sha256”,headers=“(request-target) date”,signature=“ATp0r26dbMIxOopqw0OfABDT7CKMIoENumuruOtarj8n/97Q3htHFYpH8yOSQk3Z5zh8UxUym6FYTb5+A0Nz3NRsXJibnYi7brE/4tx5But9kkFGzG+xpUmimN4c3TMN7OFH//+r8hBf7BT9/GmHDUVZT2JzWGLZES2xDOUuMtA=”&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&quot;verification&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#verification&quot; aria-label=&quot;verification permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Verification&lt;/h4&gt;&lt;p&gt;Verification is somewhat straightforward if you take a look at the pseudo-code above for how to create the signature digest. If you’re using a symmetric signing mechanism, like HMAC Sha-256, then you just build the signature the same way the client did and compare the signature values. If they match then the signature is verified. For asymmetric mechanisms, like RSA, its a bit more involved. The client will have signed their data with the private key. When it reaches the server you’ll need to Base64 decode the signature, then verify that using a the corresponding public key.&lt;/p&gt;&lt;h4 id=&quot;libraries&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#libraries&quot; aria-label=&quot;libraries permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Libraries&lt;/h4&gt;&lt;p&gt;HTTP Signatures aren’t a terribly complex concept, but that doesn’t mean you should have to go write the whole system every time you’d like to consider including it in your API workflow. We decided to [[[Open Source]]] a set of libraries for multiple languages to help encourage people to try the almost-standard out.&lt;/p&gt;&lt;p&gt;Please try them out, submit issues/pull requests or simply [[[tell the world]]] to check it out — we’d love to spread the word.&lt;/p&gt;&lt;h4 id=&quot;so-what&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#so-what&quot; aria-label=&quot;so what permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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?&lt;/h4&gt;&lt;p&gt;We think that a final check as to the integrity of request/response data is important, especially in scenarios where user data is heavily involved. This mechanism provides a standardized, but flexible framework with which to work in. At Highrise we’ve been using this system successfully between some of our internal services to verify the origin of data as well as the integrity. once the system is in place its little more than after thought and is something that’s simple to monitor for failures. In world full of security issues, lets take as much care as we can in protecting our users and ourselves.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;Thanks for reading! I work at &lt;a href=&quot;https://highrisehq.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Highrise&lt;/a&gt; building a simpler CRM. If you liked this and want to hear more about software, products and the like let me know on &lt;a href=&quot;https://twitter.com/jphenow&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt;!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[New Politics and The Art of Exploitation]]></title><link>https://jphenow.com/blog/2019/06/new-politics-and-the-art-of-exploitation/</link><guid isPermaLink="false">https://jphenow.com/blog/2019/06/new-politics-and-the-art-of-exploitation/</guid><pubDate>Wed, 12 Jun 2019 15:25:40 GMT</pubDate><content:encoded></content:encoded></item><item><title><![CDATA[Creating Mutli-File Templates for Visual Studio (Mac)]]></title><description><![CDATA[At Highrise we ended up rewriting our mobile app using Xamarin — with some use of Xamarin Forms. There was a lot that went into that…]]></description><link>https://jphenow.com/blog/2019/06/creating-mutli-file-templates-for-visual-studio-(mac)/</link><guid isPermaLink="false">https://jphenow.com/blog/2019/06/creating-mutli-file-templates-for-visual-studio-(mac)/</guid><pubDate>Wed, 12 Jun 2019 15:25:40 GMT</pubDate><content:encoded>&lt;p&gt;At Highrise we ended up rewriting our mobile app using Xamarin — with some use of Xamarin Forms. There was a lot that went into that decision so I recommend this as a starting point to understand how we wound up using Xamarin and C# at a company known to work on Ruby:&lt;/p&gt;&lt;p&gt;Embed placeholder 0.006131318380667938&lt;/p&gt;&lt;p&gt;We’ve gone through a few stages of developmental enlightenment while building this app (these apps?). A description of these stages deserves it’s own series of posts, but I’ll do a quick overview to provide the background it takes to understand.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Custom file templates for Visual Studio (Mac)]]></title><description><![CDATA[Recently, we’ve been doing a little restructuring of our Xamarin-based mobile apps. We wound up with a stricter pattern for building out…]]></description><link>https://jphenow.com/blog/2017/11/custom-file-templates-for-visual-studio-(mac)/</link><guid isPermaLink="false">https://jphenow.com/blog/2017/11/custom-file-templates-for-visual-studio-(mac)/</guid><pubDate>Wed, 15 Nov 2017 20:18:19 GMT</pubDate><content:encoded>&lt;figure class=&quot;gatsby-resp-image-figure&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/17265b257bd7e4e92805c2ae9fd4b369/46378/asset-1.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.85714285714286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMCBAX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAFymUTLIB//xAAbEAABBAMAAAAAAAAAAAAAAAACAQMRIQQQMf/aAAgBAQABBQIaF+hKJDueuv/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAMAAwEAAAAAAAAAAAAAAAABAhAhI2H/2gAIAQEABj8CR0hWvDRJGP/EABsQAQEAAwADAAAAAAAAAAAAAAERACExEFFh/9oACAEBAAE/IeIVdGTUbyomJUYesV+QubBDjvx//9oADAMBAAIAAwAAABAQD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EAB4QAQABAwUBAAAAAAAAAAAAAAERACExEEFhccFR/9oACAEBAAE/ELIagJgXnjLSgKLlfvZvHTS9O3LFOZ9ax60WTKfecdaf/9k=&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;Photo by [Juan Di Nella](https://unsplash.com/photos/OUgLA2unwtg?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText)&quot; title=&quot;Photo by [Juan Di Nella](https://unsplash.com/photos/OUgLA2unwtg?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText)&quot; src=&quot;/blog/static/17265b257bd7e4e92805c2ae9fd4b369/29d31/asset-1.jpg&quot; srcSet=&quot;/blog/static/17265b257bd7e4e92805c2ae9fd4b369/e52aa/asset-1.jpg 175w,/blog/static/17265b257bd7e4e92805c2ae9fd4b369/70ebb/asset-1.jpg 350w,/blog/static/17265b257bd7e4e92805c2ae9fd4b369/29d31/asset-1.jpg 700w,/blog/static/17265b257bd7e4e92805c2ae9fd4b369/9ecec/asset-1.jpg 1050w,/blog/static/17265b257bd7e4e92805c2ae9fd4b369/d165a/asset-1.jpg 1400w,/blog/static/17265b257bd7e4e92805c2ae9fd4b369/46378/asset-1.jpg 2600w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;Photo by [Juan Di Nella](https://unsplash.com/photos/OUgLA2unwtg?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText)&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;p&gt;Recently, we’ve been doing a little restructuring of our Xamarin-based mobile apps. We wound up with a stricter pattern for building out views and their elements. Coincidentally, that’s providing faster development and more freedom to focus on the meat of making the app work really well. With the new structure, we have a more standard way of building things. As that common pattern has became more obvious, though, we’ve wanted a first-class way to encourage a common style of adding to the app. Rather than truly enforcing it, though — and boxing ourselves in — we decided to make the most desirable path the easiest. We want to provide snippets or file templates to make new development as easy as possible within our internal framework. The simplest starting point is to just provide templates that are available when you create a new file in Visual Studio. Let’s talk about the research it took to create our own custom file templates for Visual Studio for Mac, how we actually created and distribute them internally, and finally, where I think Visual Studio for Mac could improve the state of things.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Side note&lt;/strong&gt;: The Story Time is a lengthy explanation of my journey to a solution, not the solution itself. If you really just want a small guide to Custom Multi-File templates on Visual Studio for Mac, &lt;a href=&quot;#b96b&quot;&gt;skip on down&lt;/a&gt;.&lt;/p&gt;&lt;h3 id=&quot;story-time&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#story-time&quot; aria-label=&quot;story time permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Story Time&lt;/h3&gt;&lt;p&gt;Before we get into the specifics of how we  built our custom templates, I’d like to discuss the work it took to learn enough to write our own custom templates. Not to disparage Microsoft, or complain about the work — as an explanation of what it took and what I’d like to help improve in the future.&lt;/p&gt;&lt;p&gt;The first thing I do in a situation such as this is hit Google with “Custom File Templates for Visual Studio.” Great, here’s a bunch of useful &lt;em&gt;and&lt;/em&gt; relevant looking links — jackpot:&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:651px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/bd805b385863fae57e51c56aadfb22f9/1ac66/asset-2.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:197.7142857142857%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAIAAABxU02MAAAACXBIWXMAAAsSAAALEgHS3X78AAAGBklEQVRIx41VWassSRGuPyD6IOLrIP5TBUHwZRjHF1ERBfFXzKKcmXP69N5dW661b5lZSy61tlT3mbn3jl7wI0kiA6oi8suILyxjjFqhldTr/rDvy5h++AiMGUw/WJxzQkgUJ0FAEUJBQKM4oZQSjLtO3m635UPcViytvpl+sowxvTFaq0cK+g4l3x0fu7lDay2lfDiNMVZQDKwZqqqQUjZNU9e1UjJNM6U050wpxTlXSo3jOAyD1ipLU6UVF0IpbbWdZqJ5oK7rtm2btjXG3N7Dstw+TPvhXKx5mvp+JUYb3ff9PUJ/94zTNM3z/Njvxrw8jHF8/MXKsux0Op6Ox5fn59fN9vnbb7evm83L67+//vp0Ptu2vdvt9/vD9XI9HPbb7avve8fTiWC6RhacYYIg8OM48n3Xc22IACYr7UFEMEEkIAD4nusACD3fhwC4rkcomZfFqnkXoDyLGPGzhxGAHLtpFjNwidOoSgiLYamleSQ9TdM4jvM8r5ErxnyMgziGNACEBFEESeAiDAPiAkTjuGu06vp5Wj6kcP2T9T6BH8Mw9G0rmqYWQnRS1qKuynIYBkupMc9lVemiUJzrqtJlpctS55kUQue5YtywSmdZ17T9GvMt7HRnu6x2V3D16cnDF5/YkDoouPh4dwY+DS8+wVHW1kOey6Y1jzt/n5FVVYUHbNe3PWD70APQdX3bh866gIMJIBRB6EHkBgHBCEEAOOOC85UwVnDnjDAIgUsRDD2PAhA6LgUgtm0SRynGieuR65VEER+GaVqLai2jNfI8LINaJrOYbhrNMvbLoJde3cZ+0d08T4uRo+7GYViGYf4BuVaWFvuD47p4v3P2e9u24e7V2bxcbMd/+eZsu4jCLMV86Mf3i/ztYy4YIhBTTCNKQhKEBAcIBwgFGBBAQppkSZolSZKEQZgmSZqklAadXFvdatsmDIIoCrM0SZI4S5M0TeI4SpNEdu0w9OouMVLJe4NLKWXbtvredus716Kvec+Z4cwI3nN+35mpKqPULPhQ12PXTpz3Uo0f3Dmv2N4Gjk8PNjrY8OqT1XDA2UX7C7QBPbv44PgAR1EkOJf3hh3eWrKu+frO3hViDxHgOGeIPYA8DzhBSCD0HO+aFwnjpVRt09RlWQkh3j6epltvlqFftJ57PWs5aTUbtXrMepx7Mys1DcP/qHkrTIunrX200dOr+3LwNgd/d4ZfPp1fDt727P1rc/VxiiCnAZ/vkrLqyzTN9yK1yqo4X44e8BCBrm8jDBCBEAOIAEA+RF6WJWWZEYrDMEzTNAwjQnAURsudbZnnOROMsaqqyiLPi6LgjI3TOM9v6jU8ZK3v1znQ91rrt/KUjWFZV8YNSztZ97yULOt40VVJWyWtyOU0zR/rc6vizAXIdsHZdnEYnB33cnVPZ+d4sY8X+3C8ghDThKKYggi1sh36QWs9juuDW4xVECNCseu5h9MBIlixqmIVF1wqKWpRVeuRcVZWJRdCiJozZvS9wsZhkKrr2laqTkppjL7937DaWlFQZJEIQJHFIvAL4mcUZMTLqrQOURHA/OGBdhKgnHi5KOV35Vnmz7vX7emwPe5P9mV/Ou0vx935sDsebc/Z7LfP281mv90cdpvD/vW4u9p2EEZvbHdtm8RRGNA8S+MoLIqsLEsheC0456wWgvNKcNbUYi1OUTNWMcaGB2Fa95y3grdtq8Qqr1LwVkqz9v18m+fbNK5rVcv/0mirrBoXZlc3uTgJCZkDUg+VYVxdvfjiRlc3cbzsbCdnJ2ZN06qmH99VucVERWIcJNQnHqQAhtAnro89GIAwCwAFOEIohD4FPgEX70qjoMjzt3ee53tKt3Vv66kWYyOGph4FH5p6MnrhbJDtOw2Y77PqrSWfnl5/9evfffrpZ7/57R++/Ga/t8HBBrur+3ryXo62g/D25J58mNeFmfof3vn3n3/+ox//5Kc/+/knv/jlF199wVhBKMYYEooIhYQgTGCUhFmelayq63VK9f3bta2L7f7xb//489//+ae//LWsyjWxeblPpNsjt2W5Td/hMW6+l97/AJ/UpP/MhOC7AAAAAElFTkSuQmCC&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 2&quot; title=&quot;asset 2&quot; src=&quot;/blog/static/bd805b385863fae57e51c56aadfb22f9/1ac66/asset-2.png&quot; srcSet=&quot;/blog/static/bd805b385863fae57e51c56aadfb22f9/4edbd/asset-2.png 175w,/blog/static/bd805b385863fae57e51c56aadfb22f9/13ae7/asset-2.png 350w,/blog/static/bd805b385863fae57e51c56aadfb22f9/1ac66/asset-2.png 651w&quot; sizes=&quot;(max-width: 651px) 100vw, 651px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;Too bad all of these are for either Visual Studio Code or Visual Studio for Windows. I learned over the course of trying to implement these templates, that the Windows version of this is entirely incompatible with the Mac version of how you’d add custom file templates. That was somewhat frustrating to realize, but I can understand. Things have changed a lot in this part of Microsoft recently and it’s hard to keep everything straight all the way down to documentation. So moving forward, we’ll have to be sure to scope our searches to Mac.&lt;/p&gt;&lt;p&gt;I was convinced, when I walked into this, that custom file templates would be like a solution configuration item or something. Perhaps there’d be an option to provide a few working templates via configuration and voila. Through my reading, it quickly became apparent that on the Mac Visual Studio, you create a full-fledged Extension and distribute that. That seems heavy handed, but I wasn’t about to walk away from this without custom templates.&lt;/p&gt;&lt;p&gt;Eventually I found my way to this &lt;a href=&quot;https://stackoverflow.com/questions/41042791/add-custom-project-template-to-visual-studio-preview-for-mac&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Stack Overflow question&lt;/a&gt; which references the &lt;a href=&quot;http://www.monodevelop.com/developers/articles/creating-a-simple-add-in/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;MonoDevelop Extension documentation&lt;/a&gt;. While reading through everything it became useful to know that Visual Studio for Mac is a continuation of Xamarin Studio which is (I think?) a superset — or perhaps just a distribution with extensions — of MonoDevelop. Once on the MonoDevelop documentation, things start to make a &lt;em&gt;little&lt;/em&gt; more sense. Reading the docs, it looks like I’ll need to install this &lt;a href=&quot;https://github.com/mhutch/MonoDevelop.AddinMaker&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Addin Maker Extension&lt;/a&gt; to Visual Studio, create a new solution, then follow the steps in these docs.&lt;/p&gt;&lt;p&gt;It’s at this point, though, that I realize the documentation, &lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/mac/extending-visual-studio-mac&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;on Microsoft&lt;/a&gt;, &lt;a href=&quot;https://developer.xamarin.com/guides/cross-platform/xamarin-studio/customizing-ide/extending_xamarin_studio_with_addins/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;on Xamarin&lt;/a&gt;, and on MonoDevelop all reference how to add a Command tool — which seems to basically execute some arbitrary code and place it in the active editor. That’s not what I want. Further reading shows a way to create Project Templates — which for some time I pursue, only to realize that they are truly &lt;em&gt;project&lt;/em&gt; templates, not file templates. At this point I had been hoping it would apply to both situations.&lt;/p&gt;&lt;p&gt;I’ve seen enough to realize that it’s time to go looking in the source. In the &lt;a href=&quot;https://github.com/mhutch/MonoDevelop.AddinMaker&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Addin Maker Extension&lt;/a&gt; source, since it’s an extension of its own. After some digging, I come across their File Templates in their &lt;a href=&quot;https://github.com/mhutch/MonoDevelop.AddinMaker/blob/master/MonoDevelop.AddinMaker/Properties/Manifest.addin.xml#L48&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Addin Manifest&lt;/a&gt; (don’t worry about fully understanding this yet, I’ll expand on actually creating an Addin in the next section). This is all well and good, but the files they reference in the manifest (like &lt;code class=&quot;language-text&quot;&gt;Templates/FileTemplate.xft.xml&lt;/code&gt;) are no where to be found. I’m not fully versed in how this project works, so pocket that for a little later. Looking back at notes, I was able to recall a forum post on Xamarin’s Forums that &lt;a href=&quot;https://forums.xamarin.com/discussion/52830/add-custom-file-templates&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;linked to an example&lt;/a&gt; in MonoDevelop itself. Finally, an &lt;a href=&quot;https://github.com/mono/monodevelop/blob/8bcbe6da9b1f1f448a755a100f24b5f57690bae0/main/src/addins/AspNet/Properties/MonoDevelop.AspNet.addin.xml#L102-L104&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;example of the Manifest format for my use case&lt;/a&gt; as well as the &lt;a href=&quot;https://github.com/mono/monodevelop/blob/8bcbe6da9b1f1f448a755a100f24b5f57690bae0/main/src/addins/AspNet/Templates/WebForms/WebForm-Empty.xft.xml&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;template format&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;So after pursuing implementing the distilled version of what I learned above — I had some final things to implement. I wanted to create 3 files in my template: A Xaml page, its code-behind, and a matching PageModel. Since we’re thin on documentation here, I found and perused &lt;a href=&quot;https://github.com/mhutch/MonoDevelop.AddinMaker/blob/master/MonoDevelop.AddinMaker/Editor/FileTemplateEditorExtension.cs#L60&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;the Schema definitions&lt;/a&gt; to learn that we can specify multiple files for a template — success! But how do I recreate the Xaml/Code-behind behavior that’s so automatic within Xamarin tools? At this point I recall, also from notes, that we have access to some of the Addins installed on the computer (which is missing some of the manifest and template definitions — otherwise all of my searching would have stopped here, a while ago). Opening &lt;code class=&quot;language-text&quot;&gt;/Applications/Visual\ Studio.app/Contents/Resources/lib/monodevelop/AddIns/Xamarin.Forms.Addin/Templates&lt;/code&gt; reveals details about how to build templates that include Xaml and code-behinds. There, we’ve got it. I’d link to the source of this, if I could find it anywhere.&lt;/p&gt;&lt;p&gt;On top of building the templates, we have to somehow distribute this extension. The main things I know: I don’t want to distribute this publicly, since it’s somewhat specific to us, and I want it to be simple to both distribute and stay up-to-date. Once again, during my short explorations, I wasn’t able to track down much on how to host your own repository. To get this over with, for now, I’ve decided to create a script that packages up the `mpack` (extension file) and pushes it to our Github releases on the Extension’s project page. Once published, we just need to tell developers to download it and install it from file. This is less than ideal, but I’ve already sunk more time into this than I had hoped.&lt;/p&gt;&lt;p&gt;The point of the above simply to illustrate that this was harder than I expected. It’s not meant to just be me complaining about the state of the art, it’s a note that this is what it took me to achieve what I set out to do. If that results in further interest to improve the system, or simply the documentation — Awesome! It’s meant to help remind myself what &lt;em&gt;I’d&lt;/em&gt; like to help improve.&lt;/p&gt;&lt;p&gt;Microsoft is doing a ton lately — that’s one of the reasons Xamarin and the tooling around it was so attractive when we set out to decide how we’d build our mobile apps. They’ve got deep changes going on in the core of how .NET operates, Visual Studio Code is changing things, Roslyn is changing things, Visual Studio for Mac (and consequently Xamarin) is changing things, .NET Core — the list seriously could take me the rest of the day to write-up. So much of what’s going on seems to be aiming at better standardization across the board — everything is operating on a different history, different scale. Things are converging and diverging at the same time because of the speed and breadth of what’s going on.&lt;/p&gt;&lt;p&gt;It’s all a mix of exciting, confusing, frustrating, and fun. I hope that Microsoft reaches a point where some of these things standardize in the next couple of years. I don’t say that with a bad taste in my mouth — I say that because that simply be amazing to use and would change the face of software as we know it, I think. That’s a cool future to look forward to.&lt;/p&gt;&lt;h3 id=&quot;how-to&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#how-to&quot; aria-label=&quot;how to permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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&lt;/h3&gt;&lt;p&gt;Enough of the soap-box, let’s talk about how to actually get some file templates. For our example, let’s build what I mentioned above: a template that comes with a Xaml page, with code-behind and separate PageModel class. Open Visual Studio for Mac, Open the Extensions Menu, and install the Addin Maker:&lt;/p&gt;&lt;img src=&quot;/blog/69cf8f84b03c7c5476b769bda3d8b104/asset-3.gif&quot; alt=&quot;Install Addin Maker&quot;/&gt;&lt;p&gt;Create a new IDE Extension solution:&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/c298a7f80292dde20137e7c555b46c52/e4a12/asset-4.png&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:73.71428571428572%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAAsSAAALEgHS3X78AAACF0lEQVQoz5WR/W/SUBiF+9dronHG6VAEYROc07nENNDCQi8wxiAxSwQUpLRAy2hvbz+Awkp723INmx9bRhZ9cn58n5yTvNSX6ilTYMFJvVSpc+VqjqvkwSlzXKZZcPiZOaLzNAtoFmTyIJsHmRyXyXHZPKCZQut7h4rtvX+wFXm8/frhVuTRs2gy/fHtwafY7rtIfC+aTL1KpKLJdXbiqe1Y+sWb/efx9E5i/0lk9xiUqWKplMlkswybzTJcsXL+w6i1ULUB6+1pY+h/HeDGAJ+LnjELCSGmaZmGYVkWIQRCSAl9qdnmRWlsTGxR1o/OZoenzofKIlFYRNh5hJ2/zM2f0nZjgAnxJUkGACCECCGqqlLiQOZFCepTqE/GKsKeQ4hPVuvTG8GEhEEQQghrtdpfme/1e6IMdUtFkwsFLRaO5/mui5cudm8EY2zbtmWaYRi6rvunWWp3RUUzob6WLy8djH3Pw3czm80W8/lqtSJXrGWhP2y1uyMFQWN6oWgbZdfFQRCQ2/xq7vB9RTNVZCnQcJwlxnijvLriliz0pW9tfjhSVWRp+sR1vbuD72mWu8JQRZaKLKhPlv8l88Kgw/fH0LhevlxulL0gCDfIQ3k0kEa6OTUntjW1N872POz7fhiuXx0GgeP5thuMFYUaybIGNeM3+r1ATUNQrbTHqTO5IwypZrNZKBQ4DlznXyiXQPWkKPR6PwEvmxxdD43CwwAAAABJRU5ErkJggg==&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 4&quot; title=&quot;asset 4&quot; src=&quot;/blog/static/c298a7f80292dde20137e7c555b46c52/8c557/asset-4.png&quot; srcSet=&quot;/blog/static/c298a7f80292dde20137e7c555b46c52/4edbd/asset-4.png 175w,/blog/static/c298a7f80292dde20137e7c555b46c52/13ae7/asset-4.png 350w,/blog/static/c298a7f80292dde20137e7c555b46c52/8c557/asset-4.png 700w,/blog/static/c298a7f80292dde20137e7c555b46c52/e4a12/asset-4.png 963w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;Open &lt;code class=&quot;language-text&quot;&gt;Properties/AddinInfo.cs&lt;/code&gt; and change the values to whatever you’d like. I do this because otherwise I forget and end up installing a bunch of oddly named extensions. This way we can better identify it as we work on it. Next, open &lt;code class=&quot;language-text&quot;&gt;Properties/Manifest.addin.xml&lt;/code&gt; and change it to:&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;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;ExtensionModel&amp;gt;
     &amp;lt;Extension path=&amp;quot;/MonoDevelop/Ide/FileTemplates&amp;quot;&amp;gt;
         &amp;lt;FileTemplate id=&amp;quot;FunPageTemplate&amp;quot; file=&amp;quot;Templates/FunPage.xml&amp;quot; /&amp;gt;
     &amp;lt;/Extension&amp;gt;
 &amp;lt;/ExtensionModel&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Next, create a &lt;code class=&quot;language-text&quot;&gt;Templates&lt;/code&gt; directory at the top of the project (not solution). We can now define the template configuration. In &lt;code class=&quot;language-text&quot;&gt;Templates/FunPage.xml&lt;/code&gt; we’ll explain the whole template:&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;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;
&amp;lt;Template&amp;gt;
     &amp;lt;!-- Template Header --&amp;gt;
     &amp;lt;TemplateConfiguration&amp;gt;
         &amp;lt;_Name&amp;gt;Fun Page with PageModel&amp;lt;/_Name&amp;gt;
         &amp;lt;_Category&amp;gt;Fun Pages&amp;lt;/_Category&amp;gt;
         &amp;lt;Icon&amp;gt;md-html-file-icon&amp;lt;/Icon&amp;gt;
         &amp;lt;LanguageName&amp;gt;C#&amp;lt;/LanguageName&amp;gt;
         &amp;lt;DefaultFilename&amp;gt;MyPage&amp;lt;/DefaultFilename&amp;gt;
         &amp;lt;_Description&amp;gt;Creates a Fun Xaml Page and a paired PageModel.&amp;lt;/_Description&amp;gt;
     &amp;lt;/TemplateConfiguration&amp;gt;

     &amp;lt;!-- Template Content --&amp;gt;
     &amp;lt;TemplateFiles&amp;gt;
         &amp;lt;File name=&amp;quot;${Name}.xaml&amp;quot;
               DefaultExtension=&amp;quot;.xaml&amp;quot;
               AddStandardHeader=&amp;quot;False&amp;quot;
               BuildAction=&amp;quot;EmbeddedResource&amp;quot;
               CustomTool=&amp;quot;MSBuild:UpdateDesignTimeXaml&amp;quot;
               SubType=&amp;quot;Designer&amp;quot;
               src=&amp;quot;./FunPage.xaml&amp;quot;/&amp;gt;
         &amp;lt;File name=&amp;quot;${Name}.xaml.cs&amp;quot;
               DependsOn=&amp;quot;${Name}.xaml&amp;quot;
               AddStandardHeader=&amp;quot;True&amp;quot;
               src=&amp;quot;./FunPage.xaml.cs&amp;quot;/&amp;gt;
         &amp;lt;File name=&amp;quot;${Name}Model.cs&amp;quot;
               AddStandardHeader=&amp;quot;True&amp;quot;
               src=&amp;quot;./FunModel.cs&amp;quot;/&amp;gt;
     &amp;lt;/TemplateFiles&amp;gt;
 &amp;lt;/Template&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note the use of the &lt;code class=&quot;language-text&quot;&gt;Name&lt;/code&gt; variable in the File definitions, as well as the attributes on the &lt;code class=&quot;language-text&quot;&gt;xaml&lt;/code&gt; file that explains the properties we’re used to seeing in Visual Studio. The &lt;code class=&quot;language-text&quot;&gt;src&lt;/code&gt; path is relative to this XML file, so inside of &lt;code class=&quot;language-text&quot;&gt;Templates/&lt;/code&gt; we’ll create a &lt;code class=&quot;language-text&quot;&gt;FunPage.xaml&lt;/code&gt; , &lt;code class=&quot;language-text&quot;&gt;FunPage.xaml.cs&lt;/code&gt; , and &lt;code class=&quot;language-text&quot;&gt;FunPageModel.cs&lt;/code&gt; . To keep the example going, I’ll put in each of those files, respectively:&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;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;ContentPage xmlns=&amp;quot;http://xamarin.com/schemas/2014/forms&amp;quot;      xmlns:x=&amp;quot;http://schemas.microsoft.com/winfx/2009/xaml&amp;quot; x:Class=&amp;quot;${Namespace}.${EscapedIdentifier}&amp;quot;&amp;gt;
   &amp;lt;ContentPage.Content&amp;gt;
   &amp;lt;/ContentPage.Content&amp;gt;
&amp;lt;/ContentPage&amp;gt;

---

 using System;
 using System.Collections.Generic;

 using Xamarin.Forms;

 namespace ${Namespace}
 {
     public partial class ${EscapedIdentifier} : ContentPage
     {
         public ${EscapedIdentifier} ()
         {
             InitializeComponent();
         }
     }
 }

---

 using System;
 using System.Windows.Input;
 using System.Collections.Generic;
 using Async = System.Threading.Tasks;

 using Xamarin.Forms;

 namespace ${Namespace}
 {
     public class ${EscapedIdentifier}Model
     {
         public ICommand ViewContentCommand { get; }

         public ${EscapedIdentifier}Model() { }
     }
 }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At this point, you should be able to build with &lt;code class=&quot;language-text&quot;&gt;Release&lt;/code&gt; configuration. You can then find the &lt;code class=&quot;language-text&quot;&gt;mpack&lt;/code&gt; (the file you can install to Visual Studio to get your template) in &lt;code class=&quot;language-text&quot;&gt;bin/Release/net461/&amp;lt;your-addin-name&amp;gt;.mpack&lt;/code&gt; .&lt;/p&gt;&lt;div class=&quot;embed&quot;&gt;&lt;img aria-hidden=&quot;true&quot; alt=&quot;image to preserve aspect ratio of the iframe&quot; src=&quot;data:image/svg+xml,%3Csvg xmlns=&amp;#x27;http://www.w3.org/2000/svg&amp;#x27; viewBox=&amp;#x27;0 0 100 52.00&amp;#x27;%3E%3C/svg%3E&quot;/&gt;&lt;iframe src=&quot;https://giphy.com/embed/zyin7TYoGmLAs/twitter/iframe&quot; allowfullscreen=&quot;&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;I don’t love relying on Visual Studio for building, since at some point I’d like to fully automate build and private distribution. To prep for that a little, I converted this to work better with &lt;code class=&quot;language-text&quot;&gt;msbuild&lt;/code&gt; and push to Github, so let’s go over that.&lt;/p&gt;&lt;p&gt;The project &lt;code class=&quot;language-text&quot;&gt;csproj&lt;/code&gt; didn’t work for me out of the box, so I deleted the &lt;code class=&quot;language-text&quot;&gt;CustomCommand&lt;/code&gt; section and added:&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;lt;Target Name=&amp;quot;AfterBuilding&amp;quot; AfterTargets=&amp;quot;Build&amp;quot;&amp;gt;
  &amp;lt;Exec Command=&amp;quot;&amp;#x27;/Applications/Visual Studio.app/Contents/MacOS/vstool&amp;#x27; setup pack &amp;lt;your-project&amp;gt;.dll&amp;quot; WorkingDirectory=&amp;quot;$(TargetDir)&amp;quot; Condition=&amp;quot;&amp;#x27;$(Configuration)&amp;#x27; == &amp;#x27;Release&amp;#x27;&amp;quot; /&amp;gt;
&amp;lt;/Target&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Be sure to change &lt;code class=&quot;language-text&quot;&gt;&amp;lt;your-project&amp;gt;&lt;/code&gt;. This is the command that takes the &lt;code class=&quot;language-text&quot;&gt;dll&lt;/code&gt; from the build and generates the &lt;code class=&quot;language-text&quot;&gt;mpack&lt;/code&gt; necessary to make your poject work like an extension. Now to build the project we can just run:&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;msbuild /t:Restore
msbuild /p:Configuration=Release&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, I wanted to use our Github Project’s releases to share the &lt;code class=&quot;language-text&quot;&gt;mpack&lt;/code&gt; with the team, for now. If you have the &lt;code class=&quot;language-text&quot;&gt;[hub](https://github.com/github/hub)&lt;/code&gt; &lt;a href=&quot;https://github.com/github/hub&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;command&lt;/a&gt;, you can use this little script I created to “release” your built code to Github:&lt;/p&gt;&lt;div class=&quot;embed-auto-height&quot;&gt;&lt;iframe id=&quot;jphenow/64c38eaa4669630f3e9a7e103b8617ce.js&quot; width=&quot;100%&quot; allowfullscreen=&quot;&quot; frameBorder=&quot;0&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;p&gt;And that’s it for an extension that provides Multi-File Templates to Visual Studio for Mac. Now, adding more should be a piece of cake. Next, let’s chat about my wishlist for how some of these things improve to make things simpler for the next person.&lt;/p&gt;&lt;h3 id=&quot;improving-the-state-of-the-art&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#improving-the-state-of-the-art&quot; aria-label=&quot;improving the state of the art permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Improving the State of the Art&lt;/h3&gt;&lt;p&gt;Part of the reason I wanted to tell the story of how I found the information it would take to solve the problem, was that it felt like a lot — more than I would have expected. I haven’t been a full time IDE user in some time, but I expected one of the benefits to be simple sharing of templates within a solution to promote keeping things standard.&lt;/p&gt;&lt;p&gt;That being said, shoving the solution to that problem into extensions makes enough sense — adds the amount of power you might want, and it’s not that complicated once you know the “right” things. In the end it was just hard to track down the “correct” information for this problem— it seems like tribal knowledge at the moment.&lt;/p&gt;&lt;p&gt;Taking the extension critique a step further — extensions are traditionally installed and updated from the Extension gallery. The gallery allows you to specify new repositories. However, I haven’t found a way to easily create our own extension repository that can be somewhat private. And really, I don’t actually care to force them to be “private,” they’re just wildly specific to our project. In my specific case, I don’t even need a repository available on the internet. I just want a solution-wide set of templates (or extensions, I suppose) that you just “get” when you’re developing on that solution.&lt;/p&gt;&lt;p&gt;Finally, as I’m sure almost everyone would love, it’d be simply amazing if there was deeper overlap between the Mac and Windows Visual Studios. Code would be kind of neat as well, but that is a wholly different thing, as far as I’m aware. It might even be silly to suggest that they could overlap with the Code app.&lt;/p&gt;&lt;p&gt;I do want to finish by expressing how, at the core of all of this, the power and extensibility that exists today is almost unfathomable. That’s one of the reasons I was a little surprised I had trouble finding the necessary guides to get going — it feels like this should be a huge feature, given attention and deeper effort to promote the open community. As soon as I had the necessary pieces for my use-case, several open source ideas came to mind. I look forward to pursuing those ideas and trying to add to the improvements I mention above.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;Cheers Microsoft and everyone involved that created the tools and libraries that made it possible at all.&lt;/p&gt;&lt;p&gt;Do you have Visual Studio for Mac Extensions you can share with us? I’d love to know what community or open source tools exist as examples that I simply didn’t come across.&lt;/p&gt;&lt;p&gt;Follow me on &lt;a href=&quot;https://twitter.com/jphenow&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt; for more rantings or check out my &lt;a href=&quot;https://jphenow.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;website&lt;/a&gt; for more info.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Sierra broke my keyboard modifier keys and I refused to wait for a fix]]></title><description><![CDATA[I’m addicted to staying up to date on software. I seem to do this to myself because of a healthy mix of personal and professional curiosity…]]></description><link>https://jphenow.com/blog/2016/09/sierra-broke-my-keyboard-modifier-keys-and-i-refused-to-wait-for-a-fix/</link><guid isPermaLink="false">https://jphenow.com/blog/2016/09/sierra-broke-my-keyboard-modifier-keys-and-i-refused-to-wait-for-a-fix/</guid><pubDate>Fri, 23 Sep 2016 17:41:08 GMT</pubDate><content:encoded>&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/431fed3c186f23f2fad5cbb18ef0c9b0/46378/asset-1.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.85714285714286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEBf/EABYBAQEBAAAAAAAAAAAAAAAAAAECA//aAAwDAQACEAMQAAABkVr7Mw0TN//EABgQAAMBAQAAAAAAAAAAAAAAAAABAhME/9oACAEBAAEFAl0WaVRgQkxDZ//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/AVn/xAAbEAACAQUAAAAAAAAAAAAAAAAAATIQMUGRof/aAAgBAQAGPwLCJPRHpav/xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhMWGR/9oACAEBAAE/IeI+VxX0fIs6sjYQyoYRbn//2gAMAwEAAgADAAAAEE/f/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAR/9oACAEDAQE/EIF//8QAFxEAAwEAAAAAAAAAAAAAAAAAARARMf/aAAgBAgEBPxAu1f/EABwQAQACAgMBAAAAAAAAAAAAAAEAESExUWGxkf/aAAgBAQABPxChXW80fWbu+wjwZTtT1PYsLK2lzEgHWIKP/9k=&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 1&quot; title=&quot;asset 1&quot; src=&quot;/blog/static/431fed3c186f23f2fad5cbb18ef0c9b0/29d31/asset-1.jpg&quot; srcSet=&quot;/blog/static/431fed3c186f23f2fad5cbb18ef0c9b0/e52aa/asset-1.jpg 175w,/blog/static/431fed3c186f23f2fad5cbb18ef0c9b0/70ebb/asset-1.jpg 350w,/blog/static/431fed3c186f23f2fad5cbb18ef0c9b0/29d31/asset-1.jpg 700w,/blog/static/431fed3c186f23f2fad5cbb18ef0c9b0/9ecec/asset-1.jpg 1050w,/blog/static/431fed3c186f23f2fad5cbb18ef0c9b0/d165a/asset-1.jpg 1400w,/blog/static/431fed3c186f23f2fad5cbb18ef0c9b0/46378/asset-1.jpg 2600w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;I’m addicted to staying up to date on software. I seem to do this to myself because of a healthy mix of personal and professional curiosity with a sprinkle of masochism. The latest update to Apple’s Desktop Operating System — titled Sierra — dropped this week and its actually been pretty stable. For years I had issues with my code for days or weeks after a major update, but that seems to have improved in the last few updates. That’s not to say there are &lt;em&gt;no&lt;/em&gt; issues though:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Plugged into a display, my computer won’t wake up without opening the laptop lid&lt;/li&gt;&lt;li&gt;Logitech mice are &lt;a href=&quot;http://www.macrumors.com/2016/09/22/wrecked-scrolling-logitech-mice/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;barely functioning&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Keyboard key modifiers have stopped working&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I’m a heavy keyboard user — I barely use a mouse at all — so that last bullet point is really tough for me to deal with. First let’s talk about what the keyboard modifiers are for. I work remotely so a lot of the time I’m working on my Macbook, using the builtin keyboard. However, sometimes I work at home with an Apple Display and an external Keyboard. I prefer a &lt;a href=&quot;http://www.coolermaster.com/peripheral/keyboards/quickfirerapid/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;mechanical keyboard&lt;/a&gt;, which tend to have the more common Windows/Linux key layout. A Macbook keyboard looks something like this:&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/cad01c32ecf44db7428fa8e497e8a8c6/9100a/asset-2.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:46.28571428571429%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB1JdrKwD/xAAXEAADAQAAAAAAAAAAAAAAAAAAARAR/9oACAEBAAEFAsqHP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABkQAAIDAQAAAAAAAAAAAAAAAAARARBRMf/aAAgBAQABPyFcFGCOr//aAAwDAQACAAMAAAAQw8//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAACAgMBAAAAAAAAAAAAAAAAARExECFBcf/aAAgBAQABPxCHgSuBoo0iv0osf//Z&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 2&quot; title=&quot;asset 2&quot; src=&quot;/blog/static/cad01c32ecf44db7428fa8e497e8a8c6/29d31/asset-2.jpg&quot; srcSet=&quot;/blog/static/cad01c32ecf44db7428fa8e497e8a8c6/e52aa/asset-2.jpg 175w,/blog/static/cad01c32ecf44db7428fa8e497e8a8c6/70ebb/asset-2.jpg 350w,/blog/static/cad01c32ecf44db7428fa8e497e8a8c6/29d31/asset-2.jpg 700w,/blog/static/cad01c32ecf44db7428fa8e497e8a8c6/9100a/asset-2.jpg 959w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;Whereas the more common layout looks more like this:&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/ba18bed99c7eaf7109da1684472a21e4/b17f8/asset-3.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:43.42857142857143%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAIDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAeYxFoH/xAAWEAADAAAAAAAAAAAAAAAAAAAQESD/2gAIAQEAAQUCDj//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAZEAACAwEAAAAAAAAAAAAAAAAAEQEgcZH/2gAIAQEAAT8hQjM8p//aAAwDAQACAAMAAAAQ8w//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAaEAADAAMBAAAAAAAAAAAAAAAAAREhQVEQ/9oACAEBAAE/EOMipytDVS51wb80f//Z&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 3&quot; title=&quot;asset 3&quot; src=&quot;/blog/static/ba18bed99c7eaf7109da1684472a21e4/29d31/asset-3.jpg&quot; srcSet=&quot;/blog/static/ba18bed99c7eaf7109da1684472a21e4/e52aa/asset-3.jpg 175w,/blog/static/ba18bed99c7eaf7109da1684472a21e4/70ebb/asset-3.jpg 350w,/blog/static/ba18bed99c7eaf7109da1684472a21e4/29d31/asset-3.jpg 700w,/blog/static/ba18bed99c7eaf7109da1684472a21e4/9ecec/asset-3.jpg 1050w,/blog/static/ba18bed99c7eaf7109da1684472a21e4/d165a/asset-3.jpg 1400w,/blog/static/ba18bed99c7eaf7109da1684472a21e4/b17f8/asset-3.jpg 1600w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;Note the that the Windows button (bottom left) acts as basically the same key as the Mac’s Command button. In Mac world, the Command button is heavily used, though. So the Alt (option) and Command (Windows key) are flipped between the two keyboards. This is a problem because my muscle memory has me used to the Command button being next to the space bar and the Option key being to the left of that.&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/8dc8ee9adfda9305c49f0b9925ec16ae/e5166/asset-4.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.85714285714286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAECAwT/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAb5FuwyxP//EABkQAQEBAAMAAAAAAAAAAAAAAAECAAMRIf/aAAgBAQABBQKrcmOwKbk8l5b3/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEC/9oACAEDAQE/AauX/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAIR/9oACAECAQE/AWU//8QAGhAAAgMBAQAAAAAAAAAAAAAAAAECESEiMv/aAAgBAQAGPwLJNSOmamy2Wej/xAAcEAEAAwACAwAAAAAAAAAAAAABABEhMUFRYYH/2gAIAQEAAT8hYJauDgjYqvS7KwS81O+FzE29z1LPT5P/2gAMAwEAAgADAAAAEH8//8QAGhEAAgIDAAAAAAAAAAAAAAAAAREAMUGR8P/aAAgBAwEBPxAtWISlrtz/xAAaEQACAgMAAAAAAAAAAAAAAAAAARExQZHw/9oACAECAQE/EGoshz2j/8QAHhABAAIBBAMAAAAAAAAAAAAAAQARITFBUdFhgbH/2gAIAQEAAT8QswCJFF6uM2fZfU7SlX4NonnC7Vx7ZeQCxeeoVQTQGLczQmA2HU//2Q==&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 4&quot; title=&quot;asset 4&quot; src=&quot;/blog/static/8dc8ee9adfda9305c49f0b9925ec16ae/29d31/asset-4.jpg&quot; srcSet=&quot;/blog/static/8dc8ee9adfda9305c49f0b9925ec16ae/e52aa/asset-4.jpg 175w,/blog/static/8dc8ee9adfda9305c49f0b9925ec16ae/70ebb/asset-4.jpg 350w,/blog/static/8dc8ee9adfda9305c49f0b9925ec16ae/29d31/asset-4.jpg 700w,/blog/static/8dc8ee9adfda9305c49f0b9925ec16ae/9ecec/asset-4.jpg 1050w,/blog/static/8dc8ee9adfda9305c49f0b9925ec16ae/e5166/asset-4.jpg 1200w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;So before Sierra, you would follow the instructions &lt;a href=&quot;https://www.engadget.com/2007/09/13/mac-101-change-keyboard-modifier-keys-with-a-windows-keyboard/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt; and move on with your life. It was a supported configuration out-of-the-box from Apple. Well, that menu still exists but the functionality seems to have broken. So, the Engineer in me went looking for a couple rolls of duct tape, because I’m not about to change my workflow.&lt;/p&gt;&lt;p&gt;After some searching I came across &lt;a href=&quot;https://pqrs.org/osx/karabiner/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Karabiner&lt;/a&gt;. This let’s you remap keys and do somewhat complicated things. It has a whole application and user interface. Rather than deal with a new user interface, I simply installed the little tool that remaps keys on the fly from &lt;a href=&quot;https://github.com/tekezo/Karabiner-Elements&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;here&lt;/a&gt;. With that I configured my key mapping in “~/.karabiner.d/configuration/karabiner.json”:&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;{
  “profiles”: [
    {
      “name”: “Keyboard”,
      “selected”: true,
      “simple_modifications”: {
        “caps_lock”: “escape”,
        &amp;quot;left_command&amp;quot;: &amp;quot;left_option&amp;quot;,
        &amp;quot;left_option&amp;quot;: &amp;quot;left_command&amp;quot;
      }
    }
  ]
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sweet, 🍰 (Piece of cake). I returned to work as normal. Later in the day I moved to my front-porch to work and was immediately discombobulated as my Macbook keyboard was now messed up (reversed Option and Command). I &lt;em&gt;could&lt;/em&gt; edit that config each time I switch keyboards, but that seems fairly tedious. With a little bit of research, I found a &lt;a href=&quot;https://github.com/tekezo/Karabiner/issues/354#issuecomment-148980744&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Github issue&lt;/a&gt; complaining about the same thing (thanks again, Internet) which referenced a tool called &lt;a href=&quot;http://www.hammerspoon.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Hammerspoon&lt;/a&gt;. Hammerspoon allows you to plug-in to certain OS events like USB device changes. This’ll work great. After installing Hammerspoon, I needed another keyboard configuration as well as a simple way to swap them:&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;// new karabiner config
{
  &amp;quot;profiles&amp;quot;: [
    {
      &amp;quot;name&amp;quot;: &amp;quot;Macbook Keyboard&amp;quot;,
      &amp;quot;selected&amp;quot;: false,
      &amp;quot;simple_modifications&amp;quot;: {
        &amp;quot;caps_lock&amp;quot;: &amp;quot;escape&amp;quot;
      }
    },
    {
      &amp;quot;name&amp;quot;: &amp;quot;External Keyboard&amp;quot;,
      &amp;quot;selected&amp;quot;: true,
      &amp;quot;simple_modifications&amp;quot;: {
        &amp;quot;caps_lock&amp;quot;: &amp;quot;escape&amp;quot;,
        &amp;quot;left_command&amp;quot;: &amp;quot;left_option&amp;quot;,
        &amp;quot;left_option&amp;quot;: &amp;quot;left_command&amp;quot;
      }
    }
  ]
}

-- ~/.hammerspoon/init.lua
local usbWatcher = nil
local home = os.getenv(&amp;quot;HOME&amp;quot;)

function usbDeviceCallback(data)
  if (data[&amp;quot;productName&amp;quot;] == &amp;quot;QuickFire Rapid keyboard&amp;quot;) then
    if (data[&amp;quot;eventType&amp;quot;] == &amp;quot;added&amp;quot;) then
      hs.execute(home .. &amp;#x27;/.hammerspoon/karabiner-switcher 1&amp;#x27;)
    elseif (data[&amp;quot;eventType&amp;quot;] == &amp;quot;removed&amp;quot;) then
      hs.execute(home .. &amp;#x27;/.hammerspoon/karabiner-switcher 0&amp;#x27;)
    end
  end
end

usbWatcher = hs.usb.watcher.new(usbDeviceCallback)
usbWatcher:start()
```![](./asset-5.png)

Look at that little Lua function that checks the keyboard being plugged in. You’ll need to make sure that “productName” matches _your_ keyboard. I got the product name by plugging in my keyboard, going to System Preferences &amp;gt; Keyboard &amp;gt; Modifier Keys and check what your keyboard name is in that keyboard dropdown. Note that “~jonphenow/.hammerspoon/karabiner-switcher” is just a little script I wrote to switch the Karabiner config around. This hasn’t been written yet, so let’s do that:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;#!/usr/bin/env ruby&lt;/p&gt;&lt;p&gt;require ‘json’&lt;/p&gt;&lt;p&gt;select = ARGV[0].to_i&lt;/p&gt;&lt;p&gt;filename = ”#{ENV[“HOME”]}/.karabiner.d/configuration/karabiner.json”
file = File.open(filename)
data = JSON.parse(file.read)
file.close&lt;/p&gt;&lt;p&gt;data[“profiles”][0][“selected”] = select == 0
data[“profiles”][1][“selected”] = select == 1&lt;/p&gt;&lt;p&gt;json = JSON.generate(data)&lt;/p&gt;&lt;p&gt;file = File.new(filename, “w”)
file.write(json)
file.close&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;
Then you’ll need “chmod +x” that file so it can be executed. I’m partial to Ruby to so I whipped that up quick, but this would be just as easy to write in another language. Basically all it does is take an index of an array and flip a boolean on the configuration. Now, select the Hammerspoon menu item and “Reload Config” and you should be able to switch between keyboards at will.

With a little bit of tinkering I’m back to my normal workflow with keyboards, now if someone would write a Logitech mouse driver real quick, that’d be 👌 by me.

---

If you enjoyed this, hit the little ❤️ and let me know [@jphenow](https://twitter.com/jphenow).


export const _frontmatter = {&amp;quot;title&amp;quot;:&amp;quot;Sierra broke my keyboard modifier keys and I refused to wait for a fix&amp;quot;,&amp;quot;description&amp;quot;:&amp;quot;I’m addicted to staying up to date on software. I seem to do this to myself because of a healthy mix of personal and professional curiosity with a sprinkle of masochism. The latest update to Apple’s…&amp;quot;,&amp;quot;date&amp;quot;:&amp;quot;2016-09-23T17:41:08.046Z&amp;quot;,&amp;quot;categories&amp;quot;:[&amp;quot;Keyboard&amp;quot;,&amp;quot;Tech&amp;quot;,&amp;quot;Technology&amp;quot;,&amp;quot;Mac&amp;quot;,&amp;quot;Apple&amp;quot;],&amp;quot;published&amp;quot;:true,&amp;quot;canonical_link&amp;quot;:&amp;quot;https://medium.com/@jphenow/sierra-broke-my-keyboard-modifier-keys-and-i-refused-to-wait-for-a-fix-46a548ace044&amp;quot;,&amp;quot;redirect_from&amp;quot;:[&amp;quot;/sierra-broke-my-keyboard-modifier-keys-and-i-refused-to-wait-for-a-fix-46a548ace044&amp;quot;]}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Get your head out of your ass]]></title><description><![CDATA[Hold up. You’re still using MySQL? That’s  hilarious.   Droll  even. Let me explain all the reasons you should no longer be using MySQL…]]></description><link>https://jphenow.com/blog/2016/08/get-your-head-out-of-your-ass/</link><guid isPermaLink="false">https://jphenow.com/blog/2016/08/get-your-head-out-of-your-ass/</guid><pubDate>Tue, 02 Aug 2016 02:24:33 GMT</pubDate><content:encoded>&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/27f5d470e11d77909b0787fa7766b707/46378/asset-1.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.85714285714286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABAAC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgAB/9oADAMBAAIQAxAAAAFlgWhUGV//xAAZEAEBAQEBAQAAAAAAAAAAAAABAAISERP/2gAIAQEAAQUCMXznBd+ZVbpv/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQADEv/aAAgBAwEBPwFzC5v/xAAYEQACAwAAAAAAAAAAAAAAAAAAAQIDEv/aAAgBAgEBPwGNjZo//8QAFxABAQEBAAAAAAAAAAAAAAAAADEBEP/aAAgBAQAGPwLsVdf/xAAZEAADAQEBAAAAAAAAAAAAAAAAAREhMZH/2gAIAQEAAT8hW1g0hUOmLhuNmR56H//aAAwDAQACAAMAAAAQ3y//xAAWEQEBAQAAAAAAAAAAAAAAAAAAEVH/2gAIAQMBAT8QdOv/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAgEBPxCmt//EABsQAAIDAQEBAAAAAAAAAAAAAAEhABExUUHB/9oACAEBAAE/ELdRbalwaC2eBBqjIJt9gYHT0/IFAhwFP//Z&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 1&quot; title=&quot;asset 1&quot; src=&quot;/blog/static/27f5d470e11d77909b0787fa7766b707/29d31/asset-1.jpg&quot; srcSet=&quot;/blog/static/27f5d470e11d77909b0787fa7766b707/e52aa/asset-1.jpg 175w,/blog/static/27f5d470e11d77909b0787fa7766b707/70ebb/asset-1.jpg 350w,/blog/static/27f5d470e11d77909b0787fa7766b707/29d31/asset-1.jpg 700w,/blog/static/27f5d470e11d77909b0787fa7766b707/9ecec/asset-1.jpg 1050w,/blog/static/27f5d470e11d77909b0787fa7766b707/d165a/asset-1.jpg 1400w,/blog/static/27f5d470e11d77909b0787fa7766b707/46378/asset-1.jpg 2600w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;Hold up. You’re still using MySQL? That’s &lt;em&gt;hilarious.&lt;/em&gt; &lt;strong&gt;Droll&lt;/strong&gt; even. Let me explain all the reasons you should no longer be using MySQL.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Everyone&lt;/em&gt; is using other databases like Postgres, Cassandra, Mongo, Redis, the list goes on.&lt;/p&gt;&lt;p&gt;If you want to attract talent, you should be using more exciting technology. Exciting technology brings the talent that can work with it and create scalable systems.&lt;/p&gt;&lt;p&gt;Third parties like Heroku are making it hilariously easy to use these newer, hotter databases.&lt;/p&gt;&lt;p&gt;These other databases obviously outperform MySQL in features, recent market share and sometimes performance.&lt;/p&gt;&lt;p&gt;I know a lot of people that have been successful with things that aren’t MySQL, so you should check them out and dismiss every fact, practice and battle-tested knowledge you have on the technology.&lt;/p&gt;&lt;p&gt;Based on everything I know about software I can definitely make blanket statements about technology and how it applies to your situation. Having seen a few product life-cycles I can say, definitely, that there are global truths with the trade.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;/endsatire&lt;/p&gt;&lt;figure class=&quot;gatsby-resp-image-figure&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/51ddc6211fbc65c9e29540aeb30946a9/72e01/asset-2.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.28571428571429%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHFH4kWCaR//8QAGhABAQACAwAAAAAAAAAAAAAAAQIDEhEyQv/aAAgBAQABBQLxkrWh5Cdh7RlYP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABkQAQEAAwEAAAAAAAAAAAAAABEAAQIxQf/aAAgBAQAGPwK6+E4hLaL/xAAbEAEAAgMBAQAAAAAAAAAAAAABACERMUFRYf/aAAgBAQABPyFHD7L0ut4hchlVs7iaxoZjsEn/2gAMAwEAAgADAAAAEKMv/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/EJGP/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARITFRQf/aAAgBAQABPxDJmOlvlVCfzLeN7y4GaysY2cjQFrPedjAqkUXdbNWgpfyf/9k=&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;Absolutes are for the Dark Side&quot; title=&quot;Absolutes are for the Dark Side&quot; src=&quot;/blog/static/51ddc6211fbc65c9e29540aeb30946a9/29d31/asset-2.jpg&quot; srcSet=&quot;/blog/static/51ddc6211fbc65c9e29540aeb30946a9/e52aa/asset-2.jpg 175w,/blog/static/51ddc6211fbc65c9e29540aeb30946a9/70ebb/asset-2.jpg 350w,/blog/static/51ddc6211fbc65c9e29540aeb30946a9/29d31/asset-2.jpg 700w,/blog/static/51ddc6211fbc65c9e29540aeb30946a9/72e01/asset-2.jpg 1024w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;Absolutes are for the Dark Side&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;p&gt;People make jabs at the technology or patterns used for projects all the time. Some of it is constructive, some of it isn’t. People who don’t have a stake in the actual project or an understanding of its context provide as much utility as a bloated, orange butternut squash.&lt;/p&gt;&lt;p&gt;Saying something like “wow, why wouldn’t you be using (AWS) Lambda for that,” shows that they have no understanding or respect for the history of the decisions that led to the current state. It also disrespects the fact that not everyone reads Hacker News every morning and evening obsessing over the hottest tech that will be under-supported and disappear in a year. Similarly not everyone has the same background or understanding of “what’s available.”&lt;/p&gt;&lt;p&gt;So talking more constructively is somewhat straightforward. Put half a thought towards how one might receive a condescending remark about the choices made and consider rewording your assertion.&lt;/p&gt;&lt;p&gt;More important than projecting your thoughts onto someone else’s situation, though, consider that perhaps they’ve solved the situation better than you can in a tweet, because of the having-context-and-already-did-it thing. Or perhaps this technology has been around for a few years and they’re using the tools available to them. If that’s the case, some projects reach point where swapping technology or patterns just because its what the kids are doing, would in fact be counter-productive in terms of the business making money.&lt;/p&gt;&lt;p&gt;We Software Engineers have a knack for forgetting about the balance between producing things that return dollars and bickering about the current technology we’d like to work with. As a born and bred Software nerd I can say that I fall victim this all too often, but let’s not forget why we’re here.&lt;/p&gt;&lt;p&gt;Don’t get me wrong I love the new things out of the Tech world to play with and potentially use on my projects: React, Schemaless, Lambda, we’re living in an interesting time and they’re all terribly interesting. I wouldn’t be a Software Engineer if I weren’t the least bit curious to try them and catch some news as things evolve over the years.&lt;/p&gt;&lt;p&gt;No, I love the technology. Perhaps, though, sometimes myself, Tech people, Software people and the like have to remember that a new product out of Amazon, Facebook or Uber doesn’t warrant the distaste of battle-tested systems that already solve our problems for the product that already exists and can (or does) make us money.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;Thanks for making it through my mini-rant. Please follow me on &lt;a href=&quot;https://twitter.com/jphenow&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt;!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Feeling Safe Across Data Centers]]></title><description><![CDATA[In a perfect world all of your servers are hard-wired to each other in a room. There would be one opening with which the world connects to…]]></description><link>https://jphenow.com/blog/2016/06/feeling-safe-across-data-centers/</link><guid isPermaLink="false">https://jphenow.com/blog/2016/06/feeling-safe-across-data-centers/</guid><pubDate>Wed, 29 Jun 2016 15:15:32 GMT</pubDate><content:encoded>&lt;figure class=&quot;gatsby-resp-image-figure&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/7755816cc7c632525ded6c7159c07110/47311/asset-1.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.28571428571429%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDAf/EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABTErlMkV//8QAGhABAAMAAwAAAAAAAAAAAAAAAQIDEgAhIv/aAAgBAQABBQLwxz0lfM7ZV5ZrF//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAECAQE/Aar/xAAcEAACAQUBAAAAAAAAAAAAAAAAAREQITEyUXH/2gAIAQEABj8CsnNMHPEbEH//xAAcEAADAQACAwAAAAAAAAAAAAAAAREhMWGBkaH/2gAIAQEAAT8hcwkuJO8Yk9b4LiNbCLr0alfB/9oADAMBAAIAAwAAABAcD//EABcRAQADAAAAAAAAAAAAAAAAAAABESH/2gAIAQMBAT8QqWv/xAAVEQEBAAAAAAAAAAAAAAAAAAARAP/aAAgBAgEBPxAML//EAB4QAQEAAgEFAQAAAAAAAAAAAAERADEhQWFxkaHR/9oACAEBAAE/EOQ6IFAfEyvUW7h764YKZuq/McAOEIT7iTLDUBz2yMSDcfmf/9k=&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;The Single Server Room&quot; title=&quot;The Single Server Room&quot; src=&quot;/blog/static/7755816cc7c632525ded6c7159c07110/29d31/asset-1.jpg&quot; srcSet=&quot;/blog/static/7755816cc7c632525ded6c7159c07110/e52aa/asset-1.jpg 175w,/blog/static/7755816cc7c632525ded6c7159c07110/70ebb/asset-1.jpg 350w,/blog/static/7755816cc7c632525ded6c7159c07110/29d31/asset-1.jpg 700w,/blog/static/7755816cc7c632525ded6c7159c07110/9ecec/asset-1.jpg 1050w,/blog/static/7755816cc7c632525ded6c7159c07110/47311/asset-1.jpg 1080w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;The Single Server Room&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;p&gt;In a perfect world all of your servers are hard-wired to each other in a room. There would be one opening with which the world connects to your little slice of the Internet. That way all of your cross-service communication into databases, infrastructure and other services happens within the single set of servers all directly connected.&lt;/p&gt;&lt;p&gt;In the modern world we often have to reach across the Internet to access services and applications. This can be an awkward feeling and presents some unique problems. However, there are a few techniques and patterns you can use to make it a little less frightening. Let’s talk through some of the bigger concerns and what you can do about them.&lt;/p&gt;&lt;h3 id=&quot;security&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#security&quot; aria-label=&quot;security permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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 big reason reaching across data centers, even for first-party systems, can be an issue is the matter of security. There’s a base level of security you lose sending data and commands across the Internet where anyone can glance at your requests and try to decode the data or alter what’s being sent. All someone needs is a basic understanding of networking, attack techniques like &lt;a href=&quot;https://owasp.org/www-community/attacks/Manipulator-in-the-middle_attack&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Man-in-the-middle&lt;/a&gt; and perhaps &lt;a href=&quot;https://www.wireshark.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Wireshark&lt;/a&gt; to unpack your cross-service request, see sensitive data, tinker with the request and send an altered request to the final destination. Fear not, however, there are some standard techniques to mitigate this risk:&lt;/p&gt;&lt;h4 id=&quot;1-ssl&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#1-ssl&quot; aria-label=&quot;1 ssl permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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. SSL&lt;/h4&gt;&lt;p&gt;Always communicate over &lt;a href=&quot;http://info.ssl.com/article.aspx?id=10241&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;SSL&lt;/a&gt; when you’re sending requests back and forth over your systems. This is a straightforward, standard way to secure communications between two services or entities on the Web. Under the hood, SSL uses Public/Private Key encryption to secure the body of a request between two entities. Reddit, Facebook and all of your financial institutions use SSL (HTTPS) to communicate with your browser, and likely when they communicate between internal services. Its become far easier and cheaper (free) to get SSL for your services as well thanks to organizations like &lt;a href=&quot;https://letsencrypt.org/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Let’s Encrypt&lt;/a&gt;.&lt;/p&gt;&lt;h4 id=&quot;2-request-signing&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#2-request-signing&quot; aria-label=&quot;2 request signing permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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. Request Signing&lt;/h4&gt;&lt;p&gt;While communication over SSL is somewhat secure, it can &lt;a href=&quot;https://www.eff.org/deeplinks/2011/10/how-secure-https-today&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;fail&lt;/a&gt;. Or perhaps you don’t need SSL to prevent snooping, but you do want to ensure the data wasn’t tampered with. At Highrise we decided to utilize a drafted standard that is being worked on currently under &lt;a href=&quot;https://www.ietf.org&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;IETF&lt;/a&gt;, which outlines a method for &lt;a href=&quot;https://tools.ietf.org/html/draft-cavage-http-signatures-05&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;signing a request&lt;/a&gt;. This means you can use an encryption algorithm and set of keys that you configure to define a formal verification for the &lt;em&gt;content&lt;/em&gt; of your request. Let’s say I want to &lt;em&gt;ensure&lt;/em&gt; that the Digest, Authentication and Date headers were specifically never altered. By following this protocol I would: Set up the request, retrieve the signature (using signing keys) for the specified headers, add the signature to the request and execute the request. This standard allows for specifying what keys you used to sign the request (via a KeyId parameter), which headers were signed, and which algorithm was used to do the signing. The recipient server can use this information to verify the contents of those headers were not altered during transport. The details of this freshly forming protocol go a fair bit deeper and are worth understanding. There will be a followup post directed at this topic shortly.&lt;/p&gt;&lt;p&gt;These two protocols give us a stronger confidence in the things being sent over the wire to other services.&lt;/p&gt;&lt;h3 id=&quot;reliability&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#reliability&quot; aria-label=&quot;reliability permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Reliability&lt;/h3&gt;&lt;p&gt;Speed of accessing external services due to network fluctuations as well as actual downtime are facts of a cross-data-center world. Obviously, both types of issues can compound themselves and start making whole services virtually unusable. You often won’t be able to stop these things from happening so you have to prepare for them. Let’s talk about four mitigation techniques:&lt;/p&gt;&lt;h4 id=&quot;1-local-caches-avoid-making-requests&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#1-local-caches-avoid-making-requests&quot; aria-label=&quot;1 local caches avoid making requests permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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. Local caches, Avoid making requests&lt;/h4&gt;&lt;p&gt;Caching or intelligently deciding when to request across services can cut down on the number of actual requests you need to make. Things like &lt;a href=&quot;https://en.wikipedia.org/wiki/HTTP_ETag&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;eTags&lt;/a&gt; can help with this as well as expiration headers or simply not requesting data unless you absolutely need it to accomplish your task. If the thing didn’t change from the last time it was requested let the client reuse the data it already has.&lt;/p&gt;&lt;h4 id=&quot;2-timeout-retry&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#2-timeout-retry&quot; aria-label=&quot;2 timeout retry permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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. Timeout Retry&lt;/h4&gt;&lt;p&gt;I mentioned earlier that slow responses from external services can create a compounding problem for your system. You can mitigate this risk by planning for it to happen and wrapping specific patterns around your communication. Specifically, set reasonable timeouts when you make external requests. One problem with timeouts is that you can’t tell if it ever &lt;em&gt;reached&lt;/em&gt; the server. So you should plan to make your endpoint idempotent whenever possible. Idempotent endpoints make retries simpler as well, since you can just keep hitting the endpoint and expect no unexpected change. Finally, you maybe should slow down rescheduling the request to give some time for a system to recover or avoid hammering the service. This is called &lt;strong&gt;exponential back-off.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;At Highrise, certain important requests have a timeout like 1 second. If the request fails it will be retried 3 times before it stops trying and starts messaging our team about issues. Each time it will schedule the job to retry further out: 3 seconds after failure, 9 seconds after failure and 27 seconds after failure, because of the exponential back-off algorithm. In cases where something is, for instance, sending an email via an external request, idempotency is a very serious concern so that you avoid sending the exact same email 3 times because of retries. You can accomplish something like that with a key that the server uses to decide if that operation has already been accomplished.&lt;/p&gt;&lt;h4 id=&quot;3-circuit-breakers&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#3-circuit-breakers&quot; aria-label=&quot;3 circuit breakers permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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. Circuit Breakers&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;http://martinfowler.com/bliki/CircuitBreaker.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Circuit Breakers&lt;/a&gt; paired with timeouts can help you both better handle full-service degradation and provide a window for recovery. A Circuit Breaker basically lets you define a set of rules that says when a breaker should “trip.” When a breaker trips you skip over an operation and instead respond with “try again later please,” re-queue a job or use some other retry mechanism. In practice at Highrise, we wrap requests to an external service in a circuit breaker. If the breaker trips due to too many request timeouts, we display a message to any users trying to access functionality that would use that service, and put jobs on hold that use that service. Jobs that were in-flight will presumably fail and be retried as usual. A tripped breaker stays tripped for several minutes (a configured value) and thus keeps us from hammering a service that may be struggling to keep up. This gives Operations some breathing room to add servers, fix a bug or simply allow network latency to recover a little.&lt;/p&gt;&lt;h4 id=&quot;4-upcheck&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#4-upcheck&quot; aria-label=&quot;4 upcheck permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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. Upcheck&lt;/h4&gt;&lt;p&gt;Upchecks, Health-Checks and the like are very useful to get a basic understanding of whether you can reach a service. &lt;a href=&quot;https://github.com/sportngin/okcomputer&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Libraries&lt;/a&gt; standardize some of this for you so you don’t have to think much about what to provide. Really what you want is to understand whether you can reach the service and if its basic functions are operational. Upchecks paired with a circuit breaker can help decide whether to show a maintenance page or to skip jobs that won’t work at the moment. These checks should be extremely fast. At Highrise for our first-party, external services we check once on each web-request for the livelihood of a feature about to be accessed. Again let’s say we have an external emailing service. If someone goes to the email feature we wouldn’t check at each email operation, in the code, that the service is up. Instead, we would check at the beginning of the web request if the email service is up. If it is up continue to the feature, if it isn’t display a basic “down, please try later” message.&lt;/p&gt;&lt;h3 id=&quot;act-like-it-isnt-yours&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#act-like-it-isnt-yours&quot; aria-label=&quot;act like it isnt yours permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Act like it isn’t yours&lt;/h3&gt;&lt;p&gt;When it comes to external services, even if you wrote it, you have to act like you have no control of it. You can’t assume any external service will always operate normally. The reality is you have limited control, so you have to design a system that explains issues to your users as they happen and mostly recovers on its own. Protect what you &lt;em&gt;can&lt;/em&gt; control and avoid requiring humans to repair issues like this. The more your computers can recover on their own, the more you can worry about the next feature, the next user or the next beer.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;I’m a Software Engineer at &lt;a href=&quot;https://highrisehq.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Highrise&lt;/a&gt; (&lt;a href=&quot;https://twitter.com/highrise&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@highrise&lt;/a&gt;). Follow me on Twitter to tell me what you think, as well as find more ramblings about Software and the world by me &lt;a href=&quot;https://twitter.com/jphenow&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;@jphenow&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Balance Driven Development]]></title><description><![CDATA[I mentioned in my  last post  that I would talk about my opinions on TDD, so here it is. Kicking it off, I will explain what TDD is, how it…]]></description><link>https://jphenow.com/blog/2016/05/balance-driven-development/</link><guid isPermaLink="false">https://jphenow.com/blog/2016/05/balance-driven-development/</guid><pubDate>Fri, 20 May 2016 13:58:50 GMT</pubDate><content:encoded>&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/fc8a69ae130f25930aa5025b2183d06c/46378/asset-1.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.85714285714286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABAAD/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQD/2gAMAwEAAhADEAAAAXZDkbHo/8QAGRAAAgMBAAAAAAAAAAAAAAAAAQIAERID/9oACAEBAAEFAoSAajdmpzNtn//EABURAQEAAAAAAAAAAAAAAAAAAAAS/9oACAEDAQE/AYQ//8QAFREBAQAAAAAAAAAAAAAAAAAAABL/2gAIAQIBAT8Btb//xAAbEAACAgMBAAAAAAAAAAAAAAAAAREhIjEykf/aAAgBAQAGPwLT8EodnLNsmXiLJ2j/xAAdEAEAAQMFAAAAAAAAAAAAAAABABEhQTFRYYHw/9oACAEBAAE/IaEzG6k9yB4BneMusVryiuQn/9oADAMBAAIAAwAAABDwP//EABYRAQEBAAAAAAAAAAAAAAAAAAARAf/aAAgBAwEBPxCNS//EABYRAQEBAAAAAAAAAAAAAAAAAAARAf/aAAgBAgEBPxCsU//EAB4QAQADAAICAwAAAAAAAAAAAAEAESExQWGBkaHw/9oACAEBAAE/EFuz2hFC0B00XhHX5/cAJuwdfhCLSwmzb5gxpVWzNc43if/Z&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 1&quot; title=&quot;asset 1&quot; src=&quot;/blog/static/fc8a69ae130f25930aa5025b2183d06c/29d31/asset-1.jpg&quot; srcSet=&quot;/blog/static/fc8a69ae130f25930aa5025b2183d06c/e52aa/asset-1.jpg 175w,/blog/static/fc8a69ae130f25930aa5025b2183d06c/70ebb/asset-1.jpg 350w,/blog/static/fc8a69ae130f25930aa5025b2183d06c/29d31/asset-1.jpg 700w,/blog/static/fc8a69ae130f25930aa5025b2183d06c/9ecec/asset-1.jpg 1050w,/blog/static/fc8a69ae130f25930aa5025b2183d06c/d165a/asset-1.jpg 1400w,/blog/static/fc8a69ae130f25930aa5025b2183d06c/46378/asset-1.jpg 2600w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;I mentioned in my &lt;a href=&quot;https://m.signalvnoise.com/failure-as-progress-2596a1bb067&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;last post&lt;/a&gt; that I would talk about my opinions on TDD, so here it is. Kicking it off, I will explain what TDD is, how it’s meant to work. Then I’ll explain what some people have said about it and talk about what &lt;em&gt;I&lt;/em&gt; believe the real benefits of TDD are. Finally, I’ll walk through whether I think it’s worth using and explain my use of the practice. Oh, and I’ll also provide a disclaimer as to what the heck possessed me to pile onto this already well-discussed topic.&lt;/p&gt;&lt;p&gt;TDD stands for “Test Driven Development.” At its core, it’s a development practice; a way to approach writing code. The rules of how to practice TDD are fairly simple at their surface. Say you have a new function that you need in order to accomplish a task: write the smallest test you can imagine, run the test, watch it respond with a failure, write the smallest possible amount of code to make that test pass, repeat until the necessary functionality is complete. With that process there are a number of benefits that people reference.&lt;/p&gt;&lt;p&gt;The main benefit I see TDD-promoters reference is test coverage. Since, with TDD, testing is part of how you write code, you just get more tests that are very well tied to the logic inside your functions. That test coverage paired with ongoing use of the practice tends to make new development less frightening because you have pretty high confidence that your code is covered and will alert you to unexpected behavior changes.&lt;/p&gt;&lt;p&gt;One counter-argument to the test coverage benefit is that the immense depth at which you’re covering your code in this type of practice results in brittle &lt;strong&gt;tests&lt;/strong&gt;. Growing the test code at a rate faster than your app code can increasingly make it &lt;strong&gt;difficult&lt;/strong&gt; to make changes to your app without spending many more hours rejiggering your tests. So, while you maybe have higher confidence in your app at one point, by the time you’ve redone much of your testing, due to feature additions, you’re in kind of a ¯\_(ツ)_/¯ state. So much so that by the time you’re done getting the tests green, you can’t tell if you’ve fixed the tests properly or if you just made them &lt;em&gt;look&lt;/em&gt; green.&lt;/p&gt;&lt;p&gt;As Software Engineers we like to find processes and tools that allow us to remove blame and responsibility from the human. We want the computer and process to protect us and keep us in a safe zone. I think both of the above arguments are trying to achieve that same end of some kind of safe zone. TDD, in terms of the testing benefit that’s often referenced, would like to keep us in a zone of constant “yes it works.” The anti-TDD position explains a world where the process potentially slows down our ability to progress and potentially hurts our confidence in new functionality due to lots of changing tests.&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/98118db63032a9b88ba7b32eb2428cc9/e5166/asset-2.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.85714285714286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQCA//EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAGXCZOqQn//xAAbEAACAgMBAAAAAAAAAAAAAAABAgADBBESMf/aAAgBAQABBQI28sbdzvcyVCsBD7//xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAIAQMBAT8BiY//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAQQERAhBC/9oACAEBAAY/AqxQjkuHv//EABsQAAICAwEAAAAAAAAAAAAAAAABETEhQaGB/9oACAEBAAE/IbLdJY+bfArO3BrJm0T+mMD/2gAMAwEAAgADAAAAEDz/AP/EABYRAQEBAAAAAAAAAAAAAAAAAAABYf/aAAgBAwEBPxCwyf/EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAgEBPxAbW//EABwQAQACAgMBAAAAAAAAAAAAAAEAESExUWGBkf/aAAgBAQABPxA0EG4Ga6qLDahjTyAMB1Y+Q1h9jV7gFNKoeILuE//Z&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 2&quot; title=&quot;asset 2&quot; src=&quot;/blog/static/98118db63032a9b88ba7b32eb2428cc9/29d31/asset-2.jpg&quot; srcSet=&quot;/blog/static/98118db63032a9b88ba7b32eb2428cc9/e52aa/asset-2.jpg 175w,/blog/static/98118db63032a9b88ba7b32eb2428cc9/70ebb/asset-2.jpg 350w,/blog/static/98118db63032a9b88ba7b32eb2428cc9/29d31/asset-2.jpg 700w,/blog/static/98118db63032a9b88ba7b32eb2428cc9/9ecec/asset-2.jpg 1050w,/blog/static/98118db63032a9b88ba7b32eb2428cc9/e5166/asset-2.jpg 1200w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;One of the tricks with the name TDD is that it implies that tests are the benefit, when in fact they’re simply a vehicle for development. I actually liken tests &lt;em&gt;from&lt;/em&gt; the TDD process to CO2 — they’re there to move things forward and useful for that but otherwise need to be cleaned up after their purpose has been served. That is to say that a lot of tests I write during a TDD exercise are meant to be deleted at the end. I tend to use those TDD tests to help write &lt;em&gt;new&lt;/em&gt; tests that are intended to live on with the app for regression and documentation. They often even look very similar, but now I’m writing tests to lasts rather than tests drive development. These are fundamentally different mindsets.&lt;/p&gt;&lt;p&gt;I’ve mentioned that TDD is more of a vehicle for development. The effect TDD can have on the design of your code seems to be the most overlooked benefit of the practice while still the most important, in my mind. When I’m writing code without some sort of test I just add things and out comes the functionality. I’m worried about how easiest I can get the feature done. When I’m writing it from the perspective of a test I’m writing as if I’m a &lt;strong&gt;user&lt;/strong&gt; of the code that I need. That means that my mentality for what needs to be written is altered. I’m basically defining the API that I can test and understand. This is much different than writing a bunch of things that technically work but then having to explain that API from the reverse — in order to write the tests.&lt;/p&gt;&lt;p&gt;With code/API-design and test coverage being the main arguments for or against TDD lets talk about what &lt;em&gt;I&lt;/em&gt; do. I tend to think that when there are two big camps of people shouting for or against an idea the truth or the best path lies somewhere in the middle. I think some of what you can learn about your code for &lt;em&gt;future&lt;/em&gt; testing and for understanding design is an enormous win. I don’t feel that my longer-term regression tests come from the practice, though. So after working with TDD for quite some time, I now lean on it as a tool in by toolbox. Generally, I remove those initial tests and move on with life. One thing I will give TDD is that the design mentality around understanding what your external API looks and feels like has ultimately changed how I write code, regardless of whether I’m actually living by the practice. Now, when I write code I tend to sketch up an API of what I’d expect to use, then I aim to fill that in. The same idea as TDD in terms of thinking from the other end, with less rigidity.&lt;/p&gt;&lt;p&gt;So what should &lt;em&gt;you&lt;/em&gt; do? If you’ve never tried it, don’t just listen to me or to the others on the all-knowing Internet. Try it! I still think its a practice worth doing for a little while, if only to understand it yourself and develop your own opinion. Your opinion may be different than others’ and that’s ok. If it helps you make cool things or enables you or your company to make money, then that’s awesome; keep doing that.&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/123df614f5ad63b0f328b3418b1ae720/e5166/asset-3.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:150.28571428571428%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAeABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFAv/EABcBAAMBAAAAAAAAAAAAAAAAAAABAgP/2gAMAwEAAhADEAAAAVW18vNoaE49ONoq4Rya/8QAHRAAAgICAwEAAAAAAAAAAAAAAAIBAxMhERIiMf/aAAgBAQABBQKEF+dB9FfMCxppytXCKZUEGf1Fp//EABcRAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQMBAT8BSipBSGH/xAAXEQEBAQEAAAAAAAAAAAAAAAAAAREh/9oACAECAQE/Ab1qsf/EABsQAAIDAAMAAAAAAAAAAAAAAAABEBExEiGR/9oACAEBAAY/AowVMyoXFG+xcdo//8QAGxAAAgMBAQEAAAAAAAAAAAAAAAERITFBcYH/2gAIAQEAAT8hiK7wm7F8SSJtn1vTrn6QF1aeA42Dk6x4psjbWIjRn//aAAwDAQACAAMAAAAQ38lB/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAERIf/aAAgBAwEBPxADLDpI/wD/xAAXEQEBAQEAAAAAAAAAAAAAAAABEQAQ/9oACAECAQE/EFU5CsNW/8QAHBABAAIDAQEBAAAAAAAAAAAAAQARITFBUXGx/9oACAEBAAE/ECJ1dQYKuhm6hsjfXsrQhUGvSVaK6bn0ENDYvVUVCuhr0httVbH6hWKp2Zdw9hTlwXVvLcdn2bK1P//Z&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 3&quot; title=&quot;asset 3&quot; src=&quot;/blog/static/123df614f5ad63b0f328b3418b1ae720/29d31/asset-3.jpg&quot; srcSet=&quot;/blog/static/123df614f5ad63b0f328b3418b1ae720/e52aa/asset-3.jpg 175w,/blog/static/123df614f5ad63b0f328b3418b1ae720/70ebb/asset-3.jpg 350w,/blog/static/123df614f5ad63b0f328b3418b1ae720/29d31/asset-3.jpg 700w,/blog/static/123df614f5ad63b0f328b3418b1ae720/9ecec/asset-3.jpg 1050w,/blog/static/123df614f5ad63b0f328b3418b1ae720/e5166/asset-3.jpg 1200w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;I recognize that I’m beating a proverbial dead horse. &lt;a href=&quot;http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Everyone&lt;/a&gt; &lt;a href=&quot;http://c2.com/cgi/wiki?TestDrivenDevelopment&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;and&lt;/a&gt; &lt;a href=&quot;http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;their&lt;/a&gt; &lt;a href=&quot;http://www.jamesshore.com/Agile-Book/test_driven_development.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;mother&lt;/a&gt; &lt;a href=&quot;https://www.facebook.com/notes/kent-beck/rip-tdd/750840194948847/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;has&lt;/a&gt; &lt;a href=&quot;http://agiledata.org/essays/tdd.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;already&lt;/a&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Test-driven_development&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;written&lt;/a&gt; about their feelings on TDD, I even recycled a lot of those same arguments here. I decided to publish my own post on the topic because I feel like I’ve found a place somewhere in the middle of the argument. I think a lot of people tend to focus on picking sides and I wanted to explain that I think you can use it as a tool; a tool in your belt. It doesn’t have to be your whole world, but if you prefer that tool over another, great!&lt;/p&gt;&lt;p&gt;Also, in the last month, several people have asked about my feelings on the topic so I figured I’d compile my feelings in this format for reference.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;Thanks for listening. I work for &lt;a href=&quot;https://highrisehq.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Highrise HQ&lt;/a&gt; building a better CRM. If you liked this, you might check out my &lt;a href=&quot;https://twitter.com/jphenow&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt; for more silly opinions and feels on tech and society.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Failure as Progress]]></title><description><![CDATA[Failure has a negative connotation and reasonably so; it literally means that the thing you set out to do did not happen or happened…]]></description><link>https://jphenow.com/blog/2016/05/failure-as-progress/</link><guid isPermaLink="false">https://jphenow.com/blog/2016/05/failure-as-progress/</guid><pubDate>Wed, 18 May 2016 14:36:35 GMT</pubDate><content:encoded>&lt;span class=&quot;gatsby-resp-image-wrapper&quot; style=&quot;position:relative;display:block;margin-left:auto;margin-right:auto;max-width:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/db903b6e8e8bd5a067b29f9d63ab8147/46378/asset-1.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:66.85714285714286%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDBP/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAABmY2iyBl//8QAGRAAAwEBAQAAAAAAAAAAAAAAAAECAxET/9oACAEBAAEFApz6VmORa0j3oej7/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8BiP/EABYRAQEBAAAAAAAAAAAAAAAAAAAREv/aAAgBAgEBPwHSv//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABkQAQACAwAAAAAAAAAAAAAAAAABESExQf/aAAgBAQABPyGgp4ytamVYP//aAAwDAQACAAMAAAAQSN//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPxBp/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxAP/8QAGxABAAICAwAAAAAAAAAAAAAAAQARITFRkaH/2gAIAQEAAT8QMEqKHC5Q8QTJ7hAr7H6N8z//2Q==&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;asset 1&quot; title=&quot;asset 1&quot; src=&quot;/blog/static/db903b6e8e8bd5a067b29f9d63ab8147/29d31/asset-1.jpg&quot; srcSet=&quot;/blog/static/db903b6e8e8bd5a067b29f9d63ab8147/e52aa/asset-1.jpg 175w,/blog/static/db903b6e8e8bd5a067b29f9d63ab8147/70ebb/asset-1.jpg 350w,/blog/static/db903b6e8e8bd5a067b29f9d63ab8147/29d31/asset-1.jpg 700w,/blog/static/db903b6e8e8bd5a067b29f9d63ab8147/9ecec/asset-1.jpg 1050w,/blog/static/db903b6e8e8bd5a067b29f9d63ab8147/d165a/asset-1.jpg 1400w,/blog/static/db903b6e8e8bd5a067b29f9d63ab8147/46378/asset-1.jpg 2600w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;p&gt;Failure has a negative connotation and reasonably so; it literally means that the thing you set out to do did not happen or happened incorrectly. Looking at each step and being distressed by failure is not only a drag, it’s unproductive. Altering your perception and response to failure can make life an entirely more enjoyable and fruitful endeavor.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;SpaceX is a private Space Explorations and Technology company. Basically, they launch fancy rockets and eventually want to take us to Mars for colonization.&lt;/p&gt;&lt;p&gt;To make a Mars trek a reality, they have to bring the cost of a ticket down to the point where they can sell to non-millionaires. Rockets today are virtually disposable. They’re launched, debris falls to the ocean and that’s it. One big way to lower the cost of a trip could be to make rockets actually reusable. Reusable rockets are more akin to how we think of Airplanes now. Landing a large needle-shaped rocket isn’t that simple a task though. They have to correct for the speed, angle, wind conditions, everything. By my count, they’ve attempted &lt;a href=&quot;https://en.wikipedia.org/wiki/Falcon_9_booster_controlled-descent_and_landing_tests&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;12 propulsive landings&lt;/a&gt;, 3 went famously, with others having varying levels of success. Many were considered successful simply for the fact that they were able to collect a ton of data and correct their systems for the next flight.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;We are not expecting a successful attempt this time around but we are learning — John Federspiel (Lead Mechanical Design at Space X)&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Space X didn’t set out to make a rocket landing possible, work for several years and output a rocket that can land upright out on the ocean. They worked for several years using what they know as a launchpad to new questions and experiments. They measured at every step and used those measurements to make decisions about the next mission. The key to the progress is to “&lt;a href=&quot;http://www.evancarmichael.com/library/elon-musk/Lesson-2-Commit-To-Failing-In-A-New-Way.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;commit to failing in a new way.&lt;/a&gt;”&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;In order to succeed, or fail enough to succeed, you first need to define it. One of the biggest mistakes I’ve seen is when a project has significant work done without understanding what the ultimate goal is. You’re simply chipping away at something, but you have no clue what. In order to fail at a thing or succeed and move on, you have to have a tangible goal post that you’re working towards with a definition of “it worked.”&lt;/p&gt;&lt;p&gt;A concrete example of this is writing; let’s say I’d like to write more. I’ve told people I’m trying to write more and initially I &lt;em&gt;did&lt;/em&gt;. A month or two went by and someone asked, “how’s the writing going?” and I responded, “It’s going ok.” And that’s the end of it. What’s wrong with that? Well, aside from it not really going at all, I had no measurable concept of whether writing was going well. I had no baseline to measure against.&lt;/p&gt;&lt;p&gt;In an alternate universe, when I’ve decided to improve my writing, I write up that I’d like to output one post per week and publish somewhere at least once a month for the next 6 months. This time, when a friend asks how my writing has been going, I can loosely compare my actual writing to my goals and decide whether I’ve been failing at writing. If I have been failing I can adjust my expectations or better define my goals.&lt;/p&gt;&lt;p&gt;The time boxing of a goal is also important. If you have a supposed infinite amount of time to succeed or fail, then you never fail. You’re really just in a constant state of in-progress until you “succeed” which, aside from being unrealistic, doesn’t teach you anything because you don’t get to learn from any sort of failure.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;In Software Engineering there’s a well known development technique called TDD — Test Driven Development. Rather than writing code and then testing it, you write a test and then write the code that makes that test pass. One reason people find it useful is that finding proof that your code works comes fairly naturally.&lt;/p&gt;&lt;p&gt;As an Engineer, TDD sounds a little backwards; maybe I don’t know exactly what I need to write so how should I know what test to write? TDD implies that if you’re writing code before you know what you need then you haven’t thought about your problem. This act of defining success for your code forces you through the motions of understanding what you need to learn from the code, what isn’t there now that I need to be there? TDD can instill a sense of constant failure. You write a test that will fail, watch it fail, make it not fail. It provides a quick understanding that a big red “F” isn’t a bad thing, now we know something, definitively, that we didn’t know before.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;The problem with success-sans-failure is that you don’t know the range of possible failures, yet. I prefer to have failed at some point along the way because at least then you’ve picked up some more concrete understanding of the problem at hand. You might call SpaceX a Stellar example — do enough of what you know is feasible while trying to experiment with things that will fail initially. Learn from acceptable amounts of failures while succeeding enough to stay afloat.&lt;/p&gt;&lt;p&gt;When I was a Junior Software Engineer I feared some of the changes I was making. I feared them not working properly and I feared critiques, initially. I came to learn that all the critique, the failed tests, even errors in production were just a fact of progress. Remove the fear and jump in the deep end, learn. Its a lot more fun and you’ll find that you understand everything far better than if you had spent 10 times the amount of time trying to just “get it right.”&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;I’m a Software Engineer at &lt;a href=&quot;https://highrisehq.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Highrise&lt;/a&gt;. We build a Simple CRM. Check out my rants and recommendations on &lt;a href=&quot;https://twitter.com/jphenow&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;A couple footnotes for the curious. In regards to any research I did on SpaceX, most of the inspiration and some of my basic understanding comes from &lt;a href=&quot;http://waitbutwhy.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Wait But Why&lt;/a&gt;. Do check them out, but if you’re curious about the SpaceX article, specifically, &lt;a href=&quot;http://waitbutwhy.com/2015/08/how-and-why-spacex-will-colonize-mars.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;check that out here&lt;/a&gt;. There’s also some great stuff in their latest (5/6/2016) &lt;a href=&quot;https://www.youtube.com/watch?v=L0bMeDj76ig&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;launch stream video&lt;/a&gt;. My count of launches is listed in their well-groomed controlled-descent &lt;a href=&quot;https://en.wikipedia.org/wiki/Falcon_9_booster_controlled-descent_and_landing_tests&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Wikipedia article&lt;/a&gt;. I have some feelings about TDD but I didn’t want to muddy the point of the article with those feelings. I will write more explicitly about TDD (because I feel left out) but if you are interested, some assessments of the practice are worth checking out by &lt;a href=&quot;http://c2.com/cgi/wiki?TestDrivenDevelopment&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;c2&lt;/a&gt; (more of a collection) and some opposing viewpoints from &lt;a href=&quot;http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;David Heinemeier Hansson&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Technical Debt: A Game of Perspectives]]></title><description><![CDATA[In software we like to use puns and metaphors — mostly to be cute, but sometimes it gets a point across. “Technical Debt” as a term, luckily…]]></description><link>https://jphenow.com/blog/2015/12/technical-debt:-a-game-of-perspectives/</link><guid isPermaLink="false">https://jphenow.com/blog/2015/12/technical-debt:-a-game-of-perspectives/</guid><pubDate>Mon, 14 Dec 2015 23:04:55 GMT</pubDate><content:encoded>&lt;figure class=&quot;gatsby-resp-image-figure&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:700px&quot;&gt;
      &lt;a class=&quot;gatsby-resp-image-link&quot; href=&quot;/blog/static/9d4f11544042776fd533d94446e00d3f/d9c39/asset-1.jpg&quot; style=&quot;display:block&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;
    &lt;span class=&quot;gatsby-resp-image-background-image&quot; style=&quot;padding-bottom:57.14285714285714%;position:relative;bottom:0;left:0;background-image:url(&amp;#x27;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIFBP/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAABpZqMew44P//EABsQAAEEAwAAAAAAAAAAAAAAAAIAAQNBESEy/9oACAEBAAEFAoy0RZe1cvf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAgEBPwFH/8QAGhAAAQUBAAAAAAAAAAAAAAAAAQARIDFBsf/aAAgBAQAGPwI0w0Lkf//EABsQAAIDAAMAAAAAAAAAAAAAAAERACExUWGh/9oACAEBAAE/IavfQEDH53wIdO4gkqnHuaz/2gAMAwEAAgADAAAAEBQP/8QAFhEAAwAAAAAAAAAAAAAAAAAAAAER/9oACAEDAQE/EI0U/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAx/9oACAECAQE/EFMj/8QAGxABAAMBAQEBAAAAAAAAAAAAAQARITFBUbH/2gAIAQEAAT8QG1TYH1dgt5Hr8PWOgCr9FqLNhWUmRXsgZrIao9Bn/9k=&amp;#x27;);background-size:cover;display:block&quot;&gt;&lt;/span&gt;
  &lt;img class=&quot;gatsby-resp-image-image&quot; alt=&quot;Credit: unsplash.com&quot; title=&quot;Credit: unsplash.com&quot; src=&quot;/blog/static/9d4f11544042776fd533d94446e00d3f/29d31/asset-1.jpg&quot; srcSet=&quot;/blog/static/9d4f11544042776fd533d94446e00d3f/e52aa/asset-1.jpg 175w,/blog/static/9d4f11544042776fd533d94446e00d3f/70ebb/asset-1.jpg 350w,/blog/static/9d4f11544042776fd533d94446e00d3f/29d31/asset-1.jpg 700w,/blog/static/9d4f11544042776fd533d94446e00d3f/9ecec/asset-1.jpg 1050w,/blog/static/9d4f11544042776fd533d94446e00d3f/d165a/asset-1.jpg 1400w,/blog/static/9d4f11544042776fd533d94446e00d3f/d9c39/asset-1.jpg 1800w&quot; sizes=&quot;(max-width: 700px) 100vw, 700px&quot; style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;/&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&quot;gatsby-resp-image-figcaption&quot;&gt;Credit: unsplash.com&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;p&gt;In software we like to use puns and metaphors — mostly to be cute, but sometimes it gets a point across. “Technical Debt” as a term, luckily for its creator Ward Cunningham, is both cute and useful.&lt;/p&gt;&lt;p&gt;A system has Technical Debt if it incurred faults along the road to completion. These faults may be shortcomings in the design, infrastructure, test coverage or stability. The shortcomings may result in a brittle system, slower future development, numerous bugs, performance issues, the list goes on. Both engineers and product managers want these things to be resolved; however, the two groups see things very differently. Those two perspectives can look like a black-and-white conflict, but it’s really more of a spectrum and a conversation.&lt;/p&gt;&lt;p&gt;Technical Debt has varying levels of importance. People have varying levels of interest or priority they would place on this Technical Debt due to their role or perspective on the issue. From an engineering perspective, we see less bugs, faster code on a reduced-Debt horizon. From a product perspective they might feel the time needed for Debt work reduces new feature releases and current bug work. Neither perspective is necessarily wrong. Since both parties have different directives, perspectives and priorities, a common language needs to be found in order to have a productive discussion on the topic Debt.&lt;/p&gt;&lt;h3 id=&quot;flavors-of-technical-debt&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#flavors-of-technical-debt&quot; aria-label=&quot;flavors of technical debt permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Flavors of Technical Debt&lt;/h3&gt;&lt;p&gt;Technical Debt has emergency debt and reasonable debt. Think credit card debt versus a mortgage. Just like money Debt, Technical Debt is on a sliding scale of urgency. The placement on the scale is also a moving target depending on what’s currently being worked on or what will be worked on in the future. The placement on the scale is also skewed by your perspective within your team: technical lead, junior engineer, product manager, project manager, etc.&lt;/p&gt;&lt;p&gt;Let’s talk a bit about where the Debt comes from before we get in depth on perspectives and scales. Let’s say a project is distilled to the people working on the project, a timeline, and feature-set to be built. Whenever the combined result of people and time doesn’t equate to complete feature-set a few choices must be made: add more people, change the timeline or change the feature-set. &lt;a href=&quot;http://www.amazon.com/The-Mythical-Man-Month-Engineering-Anniversary/dp/0201835959&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;The Mythical Man Month&lt;/a&gt; tells us adding people is a questionable decision depending on where in the project you’re at. Let’s say you manage to find a way to keep the timeline and the feature-set. Generally that brings in a fourth component to our project distillation: design integrity. If you lower the quality of the internals of your system, or leave out any future consideration, you may be able to hit this date with other given requirements. You will inevitably end up spending resources paying down this Debt, with interest, in the future.&lt;/p&gt;&lt;h3 id=&quot;the-parties-that-care&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#the-parties-that-care&quot; aria-label=&quot;the parties that care permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 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 Parties that Care&lt;/h3&gt;&lt;p&gt;Earlier, we talked about varying perspectives. In an organization you might see departmental roles like Engineering or Product. Personal perspectives will often come into play. Infinite things may play into each person’s understanding process. Let’s focus on the Engineering and Product relationship.&lt;/p&gt;&lt;p&gt;I’m an Engineer. Over the recent years I’ve been called a Junior Engineer, Senior Engineer, Tech Lead and part of Architecture teams. At each stage I saw things differently and so did the people around the table. I was able to use my past perspectives to mix up my thought process but I had a current role to play. As a Junior I was concerned about code style, how to get today’s bug done. As a Senior I was concerned about the quality of code coming in from the others around me, trying to set up design patterns for others to follow. I was constantly trying to invest time in bettering our code, making it more failsafe. As a Tech Lead I was explaining options we had as a team for how to build things, where the cost/benefit lay and helping the team implement those. Each role offered a new perspective, formed from a mix of what my role’s function was and what information I had at my disposal. The core decision process of an Engineer is seeking an efficient, stable and maintainable application.&lt;/p&gt;&lt;p&gt;I am not a Product Manager. However, Product Managers are often described as the CEO of their product. Their main goal is to, with the resources afforded to them, build a business around the product. They’re ultimately responsible for the business failure or success with regards to their product. Oftentimes engineers have a hard time getting the time they feel they need to get the Debt paid down on choices they made because of pressures from the Product department or above. Their goal is to build a successful business; not a science project, not a piece of art — the dollars in and the dollars out are what matter.&lt;/p&gt;&lt;p&gt;The vastly different interests of these two parties may seem tedious, but it’s very useful. You need the differing perspectives to push and pull the business in the correct direction at the correct time. Technical Debt is an example of this. Even a pragmatic engineer will occasionally obsess over the specific design of some framework or library. They’ll analyze style details, or maybe just over test their code. On the contrary, a product manager would rather see progress, features that can be added and posted on the marketing website. “When’s that next feature available? Is it shipped yet? Can I have it an hour ago?” they ask. Their role trains them to ask for the next thing or how quickly can that last bug be fixed. It can be hard to explain to a product manager that, if there are options, why the longer-route or why that bug really is worth the expense.&lt;/p&gt;&lt;h3 id=&quot;paying-it-down&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#paying-it-down&quot; aria-label=&quot;paying it down permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Paying it Down&lt;/h3&gt;&lt;p&gt;In order to argue productively about whether or not Debt is worth spending time on, you need to be able to describe the benefits or downfalls in more measurable terms. That puts the entire discussion on a level playing ground for managers and even other engineers to discuss. I may want to fix a rat’s nest of code. If I then post in Slack that I’m going to spend some time on this, some might “get” it, but others might wonder why. I could argue “it’s crappy and hard to work with,” but what does that really say? Instead, approach the assertion that we need to spend time on this Debt with something more tangible: “We use this library for all of our permissions across this platform, it takes up 2 people’s time to explain how to use it, there’s a bug reported every 2 weeks and it has performance issues that fundamentally hinder our platform’s speed.” That’s a lot of things wrong with some imaginary system and suddenly everyone understands that we have a mini fire. We just said that if we invest some time and energy into a new solution or refactored solution we could move faster as a business. Developers could work faster, not be taken away for periodic bugs and the system could run faster.&lt;/p&gt;&lt;p&gt;Use your ability to describe the measurable benefits of investing in Technical Debt to decide if it’s worth investing in at all. Fixing an ugly area of the system because it feels gross is not worthy of your time. It’s not only silly, it’s irresponsible. As far as you know, that part of the system works right now. Your “prettier, better” version that doesn’t measurably change something for the business is fundamentally scary because it’s not in production, might not work and has potential to cost more than never touching it.&lt;/p&gt;&lt;h3 id=&quot;checks--balances&quot; style=&quot;position:relative&quot;&gt;&lt;a href=&quot;#checks--balances&quot; aria-label=&quot;checks  balances permalink&quot; class=&quot;anchor before&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; focusable=&quot;false&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Checks &amp;amp; Balances&lt;/h3&gt;&lt;p&gt;Everyone needs to think about the fact that other people have different perspectives and motives. It’s not bad that they do — in fact that’s intentional, it keeps you in check. It may force you to spend more time reasoning about an argument. That time may allow you to realize that it’s not worth bringing up or give you insight into others’ reactions. It’s a superpower of sorts. One day I’ll find a way to talk in the dirt about how an engineer can avoid or fix their project’s Technical Debt infection. I know it’s a topic lots of people want concrete answers to. There is no silver bullet that I’ve found, though. You can end up with Technical Debt by over-designing a system too. With some experience it comes down to a mix pragmatism/YAGNI and forethought/design patterns.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://martinfowler.com/bliki/TechnicalDebt.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Other cool people&lt;/a&gt; &lt;a href=&quot;http://blog.codinghorror.com/paying-down-your-technical-debt/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;write about&lt;/a&gt; &lt;a href=&quot;https://www.atlassian.com/agile/technical-debt/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Technical Debt&lt;/a&gt; too.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;I am a Software Engineer at &lt;a href=&quot;https://highrisehq.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Highrise&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Find out more about me at &lt;a href=&quot;http://jphenow.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;http://jphenow.com&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Locking down with Duo]]></title><description><![CDATA[At  Highrise  we’ve been really busy improving our CRM product. Usually our focus is directly on additions or tweaks for our customers…]]></description><link>https://jphenow.com/blog/2015/11/locking-down-with-duo/</link><guid isPermaLink="false">https://jphenow.com/blog/2015/11/locking-down-with-duo/</guid><pubDate>Mon, 23 Nov 2015 21:41:45 GMT</pubDate><content:encoded>&lt;p&gt;At &lt;a href=&quot;https://highrisehq.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Highrise&lt;/a&gt; we’ve been really busy improving our CRM product. Usually our focus is directly on additions or tweaks for our customers. Currently, though, we’re also working on streamlining internally — in this case the net effect being a better, swifter support experience. Before we can add heavier admin functionality for our back-office, we need to ensure that it’s very locked down, so one of the things we’ve added internally is 2-Factor Authentication.&lt;/p&gt;&lt;p&gt;To avoid reinventing the wheel we decided to use a service to fill in some of the gaps. We chose &lt;a href=&quot;https://www.duosecurity.com/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Duo&lt;/a&gt;, which removes most compatibility concerns since it’s a fairly flexible API that does the hard work for us. Duo has a suite of &lt;a href=&quot;https://www.duosecurity.com/docs#api&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;APIs&lt;/a&gt; available to make the addition of 2-Factor Authentication secure and simple. They even have &lt;a href=&quot;https://github.com/duosecurity/duo_api_ruby&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Ruby&lt;/a&gt; &lt;a href=&quot;https://github.com/duosecurity/duo_ruby&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;libraries&lt;/a&gt;. Those libraries are just repositories, though, and not registered as gems. There’s also a Third-Party &lt;a href=&quot;https://github.com/TheKidCoder/duo-auth&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;library that is a gem&lt;/a&gt; that covers only one aspect of their API (the &lt;a href=&quot;https://www.duosecurity.com/docs/duoweb&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Web Flow&lt;/a&gt;). These options mean: deal with the libraries as non-gems (copy, or manage in non-traditional fashion) or use a gem that covers only one API topic. We opted to build out a full solution into a single gem, test it and Open Source it.&lt;/p&gt;&lt;p&gt;Thus, I give you &lt;a href=&quot;https://github.com/highrisehq/duo-api&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;duo-api&lt;/a&gt;. Duo-API is a dependency-less gem that works on Ruby all the way back to REE/1.8.7 and all the way up to latest. It provides the ability to sign and verify requests for the &lt;a href=&quot;https://www.duosecurity.com/docs/duoweb&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Duo Web Flow&lt;/a&gt; as well as connect to any of their &lt;a href=&quot;https://www.duosecurity.com/docs#api&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;APIs&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;With this addition and some of the code presented in our &lt;a href=&quot;https://github.com/highrisehq/duo-api/wiki/Duo-Web-Example&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Example&lt;/a&gt; we can now build out some of the more complex and sensitive admin functionality with peace of mind.&lt;/p&gt;&lt;p&gt;Pull Requests welcome!&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;I build software for &lt;a href=&quot;https://highrisehq.com&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Highrise&lt;/a&gt; — a more delightful CRM. Check us out!&lt;/p&gt;&lt;p&gt;By the way if you haven’t read about our awesome Support staff, check out Chris Gallo’s &lt;a href=&quot;http://blog.hotdogsandeggs.com/advice-from-the-future/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Advice From The Future&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;If you’re curious about more bite-sized commentary from me, I’m sometimes chatty on &lt;a href=&quot;https://twitter.com/jphenow&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[46 hours]]></title><description><![CDATA[365 days in a year. There’s 52 weeks somewhere in there. Each week with 7 days. Every day has 24 hours. In 1 week we have 168 hours to spend…]]></description><link>https://jphenow.com/blog/2015/11/46-hours/</link><guid isPermaLink="false">https://jphenow.com/blog/2015/11/46-hours/</guid><pubDate>Fri, 13 Nov 2015 05:58:01 GMT</pubDate><content:encoded>&lt;p&gt;365 days in a year. There’s 52 weeks somewhere in there. Each week with 7 days. Every day has 24 hours. In 1 week we have 168 hours to spend. 168 hours to work, to wrap up in each others arms, to better ourselves. It seems like so much time. All this time we have and I’m not getting everything I’d like out of it. I want to learn more, write more and strengthen some of my personal relationships, maybe make some new ones. All this time we have and I don’t know where it goes. If we could only find a little more. Sadly, for now, Time is a limited resource to us all. Let’s take a quick audit of where our precious resource is spent to understand what we have to actually working with.&lt;/p&gt;&lt;p&gt;On each day we, hopefully, sleep somewhere between 6 and 9 hours a day. I was always told to shoot for 8 hours, let’s roll with that. The average full-time employee in the US works &lt;a href=&quot;https://www.washingtonpost.com/news/on-leadership/wp/2014/09/02/the-average-work-week-is-now-47-hours/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;46.7 hours a week&lt;/a&gt;, let’s round up to 47 for a bad week. The average commute time is about 30 minutes in the US, so 1 hour for both directions, per day. Finally, let’s take out 2 hours per day for normal things like hygiene, eating breakfast/dinner and normal little tasks. That leaves us with 46 hours in a week to do whatever we want.
46 hours sounds lovely, that’s like an entire weekend!&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;He felt strangely good about having the more mundane things figured out. The rent and utilities were paid for, house supplies and the necessities like food and medicine were in a brown paper bag. Everything was finally in order. Time to let loose.&lt;/p&gt;&lt;p&gt;Feeling good about being so responsible with his initial spending, he jumps right into the good stuff. A couple beer orders, several clicks on Amazon and a few Playstation games later, our hero grows tired and decides to call it a day. He wakes up to find that he’s tight on cash somehow. The rest of the money had been spent.&lt;/p&gt;&lt;p&gt;Soon, he realizes he can’t run out and enjoy his time with friends. They want to spend money at bars or the next Bieber concert, yet he has no money with which to join them. They grow tired of lending him money when they know he doesn’t need it. They know he just spends it poorly. Many of his friends fall off and lose interest in him.&lt;/p&gt;&lt;p&gt;This continues for some time. Eventually he sees the pattern and decides to change. He becomes more careful with his spending over time. He begins approaching the decision process differently. He evolves.&lt;/p&gt;&lt;p&gt;Our hero now, when faced with decisions, thinks. If it’s absolutely necessary, just do it. If it’s not, think for a moment. “What is the product of my decision?” he thinks. He may be doing anything from climbing out of debt, to small things like spending a little on looking nicer, to not spending so much on the newest trinkets. The product of those things may be any number of things like financial stability or feeling less pressured to chase the latest thing. Just thinking for a moment changed everything.&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;46 hours to watch movies, play video games and get that side-project off the ground. &lt;strong&gt;Knuckle-Crack&lt;/strong&gt; — let’s get to it. After a few movies and getting sucked into Netflix we’re down a few hours. On to some video games to get brain function back. Let’s grab some beers. Ok, several hours of Super Meat Boy and Destiny later, it’s feeling like other types of brain cells are gone. That’s ok, we still have something like, 20 hours. Well, slept too late after the beer and staring at the screen. We’re actually closer to 12 hours now. Let’s get started on that side-project work. This is feeling difficult after everything else, accidentally ended up sitting and staring for a bit. Now there’s about an hour or two for side-project stuff. Yikes. Where did the time go? Is there anything we can do about it?&lt;/p&gt;&lt;p&gt;People often talk about money in vague terms. Podcasts like &lt;a href=&quot;https://itunes.apple.com/us/podcast/open-account-with-suchin-pak/id1037408626&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Open Account&lt;/a&gt; are trying to change that by talking more explicitly about numbers and a decision process with people who have hit bad times and good times. I’d like people to start doing the same with their time. We should take a moment to think about how we spend our time. There’s no need to pick up a project management tool and start booking all of our precious free-time. No. We just need to take a moment to reflect on time spent and evaluate the next step.&lt;/p&gt;&lt;p&gt;I have a few things that I consider when I’m thinking about my free time. I’m working on becoming more well read in a few specific topics, while simultaneously hoping to write about those topics and perhaps someday make those topics part of a living. These things while trying to keep up relationships with family and my best friends, stay healthy and become more financially stable. Take a moment to understand what you care about and spend your time like you care about those things.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; You should follow me on &lt;a href=&quot;https://twitter.com/jphenow&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot;&gt;Twitter&lt;/a&gt; where I pretend like I can talk about Software, Science and other non-controversial topics.&lt;/p&gt;</content:encoded></item></channel></rss>