<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://jbeckwith.com/blog</id>
    <title>Justin Beckwith Blog</title>
    <updated>2025-11-01T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://jbeckwith.com/blog"/>
    <subtitle>Justin Beckwith Blog</subtitle>
    <icon>https://jbeckwith.com/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Teaching Claude to be a Link Detective with linkinator-mcp]]></title>
        <id>https://jbeckwith.com/blog/2025/11/01/linkinator-mcp</id>
        <link href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp"/>
        <updated>2025-11-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The Model Context Protocol (MCP) lets you give AI assistants superpowers. I built linkinator-mcp to teach Claude Code how to scan websites for broken links interactively. Spoiler alert: it turns out AI is really good at finding 404s.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Linkinator MCP" src="https://jbeckwith.com/assets/images/linkinator-da245a1eca661c45ef870c0861bb953b.webp" width="1024" height="542" class="img_ev3q"></p>
<p>You know that feeling when you publish a website, and three months later someone tells you half the links are broken? Or worse - when you're in the middle of a deployment and you <em>know</em> there are busted links somewhere, but you have no idea where?</p>
<p>When working on API reference documentation for Google's APIs, our team ran into this a little too frequently. Enough times that I built <a href="https://github.com/JustinBeckwith/linkinator" target="_blank" rel="noopener noreferrer" class="">linkinator</a> - a tool that crawls websites and checks for broken links. It's worked well enough for me for years, but here's the thing: <strong>running a link checker from the command line is kind of a chore</strong>.</p>
<p>When running linkinator as part of CI, especially with the <a href="https://github.com/JustinBeckwith/linkinator-action" target="_blank" rel="noopener noreferrer" class="">GitHub Action</a>, it works great. It's a little less fun when you're doing the initial analysis - instead of a single broken link you've introduced, you're often presented with a seemingly insurmountable list of failures.</p>
<p>You have to remember all the flags. You have to parse the output. You have to decide what to do about the results. It's all very... manual. And as someone who's been building developer tools for a while now, I can tell you that manual processes are where good intentions go to die.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="enter-the-model-context-protocol">Enter the Model Context Protocol<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#enter-the-model-context-protocol" class="hash-link" aria-label="Direct link to Enter the Model Context Protocol" title="Direct link to Enter the Model Context Protocol" translate="no">​</a></h2>
<p>A few months ago, Anthropic released the <a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">Model Context Protocol (MCP)</a> - a way to give AI assistants like Claude access to external tools and data sources. Think of it like giving your AI a Swiss Army knife, except instead of a tiny scissors and a toothpick, it gets powerful APIs and command-line tools.</p>
<p>The protocol is pretty simple. You create a "server" (which is really just a Node.js script) that exposes some functionality, and then AI assistants can call into it to do useful work. It's like building a plugin, except the AI figures out when and how to use it.</p>
<p>And that got me thinking: <em>What if Claude could run link checks for me?</em></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-is-actually-useful">Why this is actually useful<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#why-this-is-actually-useful" class="hash-link" aria-label="Direct link to Why this is actually useful" title="Direct link to Why this is actually useful" translate="no">​</a></h2>
<p>Here's where things get interesting. When you're working with an AI assistant like Claude Code, you're often:</p>
<ul>
<li class="">Building websites or documentation</li>
<li class="">Refactoring content and moving pages around</li>
<li class="">Reviewing pull requests that touch markdown files</li>
<li class="">Debugging why that one page isn't working</li>
</ul>
<p>In all of these scenarios, having Claude be able to scan for broken links <em>in the flow of the conversation</em> is ridiculously helpful. Instead of:</p>
<ol>
<li class=""><em>"Let me check if there are any broken links"</em></li>
<li class="">Open a terminal</li>
<li class="">Run <code>npx linkinator ./docs --recurse</code></li>
<li class="">Wait for it to finish</li>
<li class="">Parse the output</li>
<li class="">Go back to Claude to discuss what you found</li>
</ol>
<p>You can just ask: <em>"Hey, can you check if there are any broken links in my docs?"</em></p>
<p>And Claude will... just do it. Then it'll tell you what it found, suggest fixes, and even help you update the files. It's the kind of workflow that feels like magic once you get used to it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-linkinator-mcp-works">How linkinator-mcp works<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#how-linkinator-mcp-works" class="hash-link" aria-label="Direct link to How linkinator-mcp works" title="Direct link to How linkinator-mcp works" translate="no">​</a></h2>
<p>Under the hood, <a href="https://github.com/JustinBeckwith/linkinator-mcp" target="_blank" rel="noopener noreferrer" class="">linkinator-mcp</a> is a thin wrapper around the linkinator library. It exposes a single MCP tool called <code>scan_page</code> that accepts all the usual linkinator options:</p>
<ul>
<li class="">Scan websites or local files</li>
<li class="">Crawl recursively across domains</li>
<li class="">Check CSS for URLs</li>
<li class="">Validate anchor fragments (those <code>#section-name</code> links)</li>
<li class="">Configure retries, timeouts, SSL handling, all the good stuff</li>
</ul>
<p>When Claude calls the tool, linkinator does its thing - crawling pages, checking links, following redirects - and then returns a nicely formatted report. Claude gets to see which links are broken, what the error was, and can then help you figure out what to do about it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="setting-it-up-its-easier-than-you-think">Setting it up (it's easier than you think)<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#setting-it-up-its-easier-than-you-think" class="hash-link" aria-label="Direct link to Setting it up (it's easier than you think)" title="Direct link to Setting it up (it's easier than you think)" translate="no">​</a></h2>
<p>The quickest way to get started is to run:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">npx install-mcp linkinator-mcp --client claude</span><br></div></code></pre></div></div>
<p>This will automatically configure linkinator-mcp for Claude Desktop, Claude Code, Cursor, and Cline. It's one of those rare cases where the "automatic setup" actually works.</p>
<p>If you want to configure it manually (or you're the kind of person who likes to know what's happening under the hood), you can edit your MCP config file directly.</p>
<p>For Claude Code on macOS/Linux, edit <code>~/.config/claude-code/config.json</code>:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"mcpServers"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"linkinator"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"command"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"npx"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"args"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"linkinator-mcp"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>On Windows, the file is at <code>%APPDATA%\claude-code\config.json</code>.</p>
<p>Restart Claude Code, and you're good to go.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-it-in-the-wild">Using it in the wild<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#using-it-in-the-wild" class="hash-link" aria-label="Direct link to Using it in the wild" title="Direct link to Using it in the wild" translate="no">​</a></h2>
<p>Here's where things get fun. Once you've got linkinator-mcp set up, you can just... ask Claude to check links. The AI figures out when to use the tool, and handles all the details.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="example-1-quick-website-scan">Example 1: Quick website scan<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#example-1-quick-website-scan" class="hash-link" aria-label="Direct link to Example 1: Quick website scan" title="Direct link to Example 1: Quick website scan" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">You: Can you check all the links on https://jbeckwith.com?</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Claude: I'll scan your website for broken links.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[Calls linkinator-mcp with path: "https://jbeckwith.com"]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Good news! All 47 links on your site are working correctly.</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="example-2-deep-recursive-scan">Example 2: Deep recursive scan<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#example-2-deep-recursive-scan" class="hash-link" aria-label="Direct link to Example 2: Deep recursive scan" title="Direct link to Example 2: Deep recursive scan" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">You: I just refactored my documentation site. Can you do a deep scan</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     to make sure I didn't break anything?</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Claude: I'll do a recursive scan of your entire site.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[Calls linkinator-mcp with path: "https://docs.example.com", recurse: true]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">I found 3 broken links:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- /old-page.html (404) - linked from /getting-started.md</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- /api/v1/docs (404) - linked from /reference.md</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- /images/diagram.png (404) - linked from /architecture.md</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Would you like me to help fix these?</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="example-3-local-development">Example 3: Local development<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#example-3-local-development" class="hash-link" aria-label="Direct link to Example 3: Local development" title="Direct link to Example 3: Local development" translate="no">​</a></h3>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">You: I'm working on this documentation in ./docs. Before I commit,</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     can you check if there are any broken links?</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Claude: I'll scan your local docs folder.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[Calls linkinator-mcp with path: "./docs", recurse: true, markdown: true]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Found 1 broken link:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- ../assets/screenshot.png (not found) - referenced in ./docs/tutorial.md</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">The file ../assets/screenshot.png doesn't exist. Did you mean</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./assets/screenshot.png instead?</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="example-4-the-paranoid-squirrel-approach">Example 4: The paranoid squirrel approach<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#example-4-the-paranoid-squirrel-approach" class="hash-link" aria-label="Direct link to Example 4: The paranoid squirrel approach" title="Direct link to Example 4: The paranoid squirrel approach" translate="no">​</a></h3>
<p>If you want to be <em>really</em> thorough (and I respect that), you can ask Claude to go full squirrel mode:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">You: Can you do a really strict scan of my site? I want to catch</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     everything - broken fragments, redirects, HTTP links, all of it.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Claude: I'll run a comprehensive scan with strict validation.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[Calls linkinator-mcp with checkFragments: true, redirects: "warn",</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> requireHttps: "warn", recurse: true]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Found several issues:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 2 broken fragment identifiers (links to sections that don't exist)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 5 HTTP links that should be HTTPS</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">- 3 redirects that could be updated to point directly</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Let me show you each one and we can fix them together.</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-i-built-this">Why I built this<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#why-i-built-this" class="hash-link" aria-label="Direct link to Why I built this" title="Direct link to Why I built this" translate="no">​</a></h2>
<p>I've been maintaining linkinator for years now, and it's been great for CI/CD pipelines and automated checks. But the truth is, most of the time when I need to check links, it's in the middle of doing something else. I'm writing docs, or reviewing a PR, or debugging a website issue.</p>
<p>Having Claude Code be able to check links <em>in context</em> - while we're already discussing the problem - is a huge workflow improvement. It's the difference between "let me go run this other tool and come back" versus "yeah, let me check that for you real quick."</p>
<p>Plus, Claude is weirdly good at interpreting the results and suggesting fixes. It understands that a 404 probably means you renamed a file and forgot to update the link. It knows that a broken fragment identifier means you changed a heading. It can see patterns in multiple broken links and suggest systematic fixes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="some-limitations-to-be-aware-of">Some limitations to be aware of<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#some-limitations-to-be-aware-of" class="hash-link" aria-label="Direct link to Some limitations to be aware of" title="Direct link to Some limitations to be aware of" translate="no">​</a></h2>
<p>Is this perfect? No. Here are a few things to keep in mind:</p>
<ul>
<li class=""><strong>It's as accurate as linkinator itself</strong>. If you've got JavaScript-rendered content or fancy client-side routing, some links might not be checkable.</li>
<li class=""><strong>Bot protection is a thing</strong>. Some sites (looking at you, LinkedIn) will block automated scanners. Linkinator handles this by skipping those links rather than marking them as broken.</li>
<li class=""><strong>Large sites take time</strong>. If you're scanning a massive website recursively, it's going to take a while. Claude is patient, but you might want to grab a coffee.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-bigger-picture">The bigger picture<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#the-bigger-picture" class="hash-link" aria-label="Direct link to The bigger picture" title="Direct link to The bigger picture" translate="no">​</a></h2>
<p>This is honestly just the beginning. MCP opens up a whole world of possibilities for making AI assistants more useful in real development workflows. I've got a few other ideas brewing:</p>
<ul>
<li class="">An MCP server for running tests and parsing results</li>
<li class="">One for interacting with GitHub Issues and PRs</li>
<li class="">Maybe one for analyzing bundle sizes or performance metrics</li>
</ul>
<p>The pattern is always the same: take a tool that developers already use, wrap it in MCP, and suddenly your AI assistant can help you use it more effectively.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-out">Try it out<a href="https://jbeckwith.com/blog/2025/11/01/linkinator-mcp#try-it-out" class="hash-link" aria-label="Direct link to Try it out" title="Direct link to Try it out" translate="no">​</a></h2>
<p>If you're using Claude Code (or any other MCP-compatible AI assistant), give linkinator-mcp a spin. The setup takes about 30 seconds, and the first time Claude catches a broken link you were about to commit, you'll be hooked.</p>
<p>Grab it from <a href="https://www.npmjs.com/package/linkinator-mcp" target="_blank" rel="noopener noreferrer" class="">npm</a> or check out the source on <a href="https://github.com/JustinBeckwith/linkinator-mcp" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>
<p>And if you build something cool with MCP, or have ideas for other tools that would be useful to wrap - let me know! I'm <a href="https://twitter.com/JustinBeckwith" target="_blank" rel="noopener noreferrer" class="">@JustinBeckwith</a> on Twitter, and I'd love to hear what you're building.</p>
<p>Now if you'll excuse me, I need to go check all the links in this blog post. <em>Recursively</em>.</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="nodejs" term="nodejs"/>
        <category label="ai" term="ai"/>
        <category label="featured" term="featured"/>
        <category label="mcp" term="mcp"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[To lock or not to lock]]></title>
        <id>https://jbeckwith.com/blog/2019/12/18/package-lock</id>
        <link href="https://jbeckwith.com/blog/2019/12/18/package-lock"/>
        <updated>2019-12-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The package-lock.json file is useful in some cases, but a problem in others. This blog post examines how package-lock.json works, the situations where it creates problems, and reccomendations on when to use them and when not to use them.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Package Lock Files" src="https://jbeckwith.com/assets/images/lock-c4fecd5a0fc516b9b5c62249f6641a9f.png" width="872" height="378" class="img_ev3q"></p>
<p>A few years ago, <a href="https://npmjs.org/" target="_blank" rel="noopener noreferrer" class="">npm</a> introduced the notion of a <a href="https://docs.npmjs.com/files/package-lock.json" target="_blank" rel="noopener noreferrer" class=""><code>package-lock.json</code></a>. The purpose of the file is to provide a manifest that calls out the exact version of every package in your tree, the last time <code>npm install</code> was run. After running <code>npm install</code>, you're going to see a message like this:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">npm notice created a lockfile as package-lock.json. You should commit this file.</span><br></div></code></pre></div></div>
<p>While this advice is well intentioned... it's not always true :) Let's talk about when you want to check this into source control, and when not to.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-package-lockjson-works">How package-lock.json works<a href="https://jbeckwith.com/blog/2019/12/18/package-lock#how-package-lockjson-works" class="hash-link" aria-label="Direct link to How package-lock.json works" title="Direct link to How package-lock.json works" translate="no">​</a></h2>
<p>The mechanics of <code>package-lock.json</code> are simple enough:</p>
<ul>
<li class="">When you run <code>npm install</code> the first time, npm automatically creates the file for you.</li>
<li class="">It has the exact version of every top level and transitive dependency in your <code>node_modules</code> folder.</li>
<li class="">When you <code>npm install some-package</code>, the lock file is updated automatically.</li>
<li class="">When you update the version of a package in your <code>package.json</code> and run <code>npm install</code>, the <code>package-lock.json</code> file will get updated automatically.</li>
</ul>
<p>If you peek inside one of these files, you're going to get a bunch of gobbledygook like this:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"@google-cloud/bigtable"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2.3.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"lockfileVersion"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"requires"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"dependencies"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"@babel/code-frame"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"7.5.5"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"resolved"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"integrity"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw=="</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"dev"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"requires"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"@babel/highlight"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"^7.0.0"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><br></div></code></pre></div></div>
<p>The next time you run <code>npm install</code>, you're (likely) going to get the exact copy of dependencies outlined in the <code>package-lock.json</code> file. If you didn't have a lock file, npm would look at every dependency in <code>package.json</code>, and find the latest compatible version of every top level and transitive dependency. Having a lock file saves you from this lookup on every install.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-lock-files-sound-great">Why lock files sound great<a href="https://jbeckwith.com/blog/2019/12/18/package-lock#why-lock-files-sound-great" class="hash-link" aria-label="Direct link to Why lock files sound great" title="Direct link to Why lock files sound great" translate="no">​</a></h2>
<p>In a world where lock files do not exist - running <code>npm install</code> is largely <a href="https://en.wikipedia.org/wiki/Idempotence" target="_blank" rel="noopener noreferrer" class="">non-idempotent</a>, or non-reproducable. Given the same set of inputs, the outputs can be different. This means that I can run <code>npm install</code> twice, and the results in the <code>node_modules</code> folder can be wildly different. Stop me if you've seen this happen before:</p>
<ul>
<li class=""><em>I just wrote some code locally, and everything works</em></li>
<li class=""><em>I go ahead and <code>git push</code> my changes. For some reason CI is breaking!?</em></li>
<li class=""><em>It's a lint error... it looks like <code>prettier</code> is failing on some formatting change</em>.</li>
</ul>
<p>This can happen because <strong>the version of <code>prettier</code> you're using locally can be different than the version of <code>prettier</code> you're getting in CI</strong>. This is one of the critical problems package lock files can solve - the version you're getting on your computer, and on CI are mostly going to be the same (there are exceptions for native modules, deleted package versions, etc).</p>
<p>Having an exact record of the full transitive dependency tree can be great for a few reasons:</p>
<ul>
<li class="">Every environment is (mostly) guaranteed to install the same set of dependencies when running <code>npm install</code></li>
<li class=""><code>npm install</code> typically runs faster because some resolution steps can be skipped</li>
<li class="">There is a log in source control of the exact tree used to run your code and tests</li>
</ul>
<p>This all sounds great, but guess what ... <em>I don't use lock files, and if you're building libraries, you probably shouldn't use lock files either</em>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-lock-files-are-not-so-great">When lock files are not so great<a href="https://jbeckwith.com/blog/2019/12/18/package-lock#when-lock-files-are-not-so-great" class="hash-link" aria-label="Direct link to When lock files are not so great" title="Direct link to When lock files are not so great" translate="no">​</a></h2>
<p>While lock files <em>sound</em> great, they come with some real baggage ranging from cosmetically annoying, to outright poor software practices. For context - my team at Google builds npm modules that other developers use to make their applications. In the context of a library, it does not make sense to use lock files (more on the end application use case later). <strong>We've broken far more customers specifically <em>because of our lock file usage</em>, and decided to start ignoring them across the ~80 or so npm modules we ship.</strong></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="generated-files-dont-belong-in-git">Generated files don't belong in git<a href="https://jbeckwith.com/blog/2019/12/18/package-lock#generated-files-dont-belong-in-git" class="hash-link" aria-label="Direct link to Generated files don't belong in git" title="Direct link to Generated files don't belong in git" translate="no">​</a></h3>
<p>The first reason I don't like lock files is largely cosmetic. <em>I generally don't like generated files to be tracked in source control</em>. I personally don't like this for a few reasons:</p>
<ul>
<li class="">They create terrible merge conflicts</li>
<li class="">They make code reviews more difficult</li>
<li class="">Things like lock file maintenance PRs muddy commit history</li>
</ul>
<p>When dealing with PRs and trying to keep them up to date I just find the ergonomics... clunky.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="youre-not-testing-reality">You're not testing reality<a href="https://jbeckwith.com/blog/2019/12/18/package-lock#youre-not-testing-reality" class="hash-link" aria-label="Direct link to You're not testing reality" title="Direct link to You're not testing reality" translate="no">​</a></h3>
<p>Way more importantly - <strong>lock files provide false comfort</strong>. You're not testing what users get. The lock file you check into source control has no material impact on the module that developers will install. <code>package-lock.json</code> is not packaged into your module, and is not delivered to developers when they <code>npm install</code> your module. It is <em>only</em> used as a library developer, during local <code>npm install</code> for developer machines, and in CI.</p>
<p>In other words - The transitive dependencies that are defined in <code>package-lock.json</code> may not at all reflect what developers see when they run <code>npm install</code>. The transitive dependencies you test against in CI may not at all reflect what developers are seeing. You are probably testing against an entirely different set of dependencies than the ones developers will see.</p>
<p>Can you see how that's a big problem? Here's how it happens:</p>
<ol>
<li class="">You have a dependency on <code>"baby-yoda": "^1.0.0"</code> in your <code>package.json</code></li>
<li class=""><code>baby-yoda@1.0.0</code> takes a dependency on <code>green-lizard@1.0.0</code></li>
<li class="">You run <code>npm install</code> - at this point in time, <code>green-lizard</code> has its <a href="https://docs.npmjs.com/cli/dist-tag" target="_blank" rel="noopener noreferrer" class="">dist-tag</a> set to <code>1.0.0</code>, and that gets written into your <code>package-lock.json</code></li>
<li class="">Your code, including the lock file, get checked into <code>git</code></li>
</ol>
<p>So let's stop, and take a breath. You installed the module <code>baby-yoda</code>, and you got a lock file that includes both <code>baby-yoda@1.0.0</code> and <code>green-lizard@1.0.0</code>. All is going well! Let's say a few weeks pass...</p>
<ol start="5">
<li class="">Somewhere over the last few weeks, <code>green-lizard</code> version <code>1.0.1</code> is released. It has a subtle breaking change that the authors missed (we ain't perfect).</li>
<li class="">Your nightly tests run, PRs are submited, and CI never notices there's a problem with <code>green-lizard@1.0.1</code>. That's because you have <code>green-lizard@1.0.0</code> in your <code>package-lock.json</code>, protecting you.</li>
<li class="">Consumers of your module are broken. They're reporting errors related to the latest version of <code>green-lizard</code>, but you can't see the problem.</li>
<li class="">You delete your <code>package-lock.json</code>, run <code>npm install</code>, and all of the sudden you can reproduce the error.</li>
</ol>
<p>We've seen this dance play out several times. We want our nightly (and presubmit) CI to test against the same set of dependencies consumers of our libraries are going to see - and lock files make that impossible.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-to-use-lock-files-and-when-not-to">When to use lock files, and when not to<a href="https://jbeckwith.com/blog/2019/12/18/package-lock#when-to-use-lock-files-and-when-not-to" class="hash-link" aria-label="Direct link to When to use lock files, and when not to" title="Direct link to When to use lock files, and when not to" translate="no">​</a></h2>
<p>Lock files shine when you're building <em>user facing applications</em>. If you're building a web application, or command line tool (that isn't <code>npm install</code>-ed), lock files protect you from the ever-changing set of transitive dependencies that make up your application. If your binary is packaging the <code>node_modules</code> folder along with your build, using a lock file is great. If you're building an npm module that you expect others to <code>npm install</code> - they aren't consumed by downstream users, and create more problems than they solve (in my opinion).</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-ignore-the-lock-file">How to ignore the lock file<a href="https://jbeckwith.com/blog/2019/12/18/package-lock#how-to-ignore-the-lock-file" class="hash-link" aria-label="Direct link to How to ignore the lock file" title="Direct link to How to ignore the lock file" translate="no">​</a></h2>
<p>The easiest way to opt out of the lock file is to add the following to your <code>.npmrc</code> file:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">package-lock=false</span><br></div></code></pre></div></div>
<p>There are a few approaches where you can find middle ground. One approach is to keep the lock file for the CI gains, but make sure to delete it as part of your nightly build workflow. This ensures CI builds are fast and consistent, but also gives you a warning when something goes awry. (<a href="https://github.com/soldair" target="_blank" rel="noopener noreferrer" class="">soldair</a> likes to call this the "broken every morning" approach). I personally don't like the concept of nightly builds, but that's a topic for another post.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="some-think-differently-and-thats-great">Some think differently, and that's great<a href="https://jbeckwith.com/blog/2019/12/18/package-lock#some-think-differently-and-thats-great" class="hash-link" aria-label="Direct link to Some think differently, and that's great" title="Direct link to Some think differently, and that's great" translate="no">​</a></h2>
<p>There are no "right" answers here. I don't speak for every engineer working on node.js at Google :) Others like lock files, and believe the positives outweight the negatives. I'd love to know what you think! If you want to chat lock files, let me know at <a href="https://twitter.com/JustinBeckwith" target="_blank" rel="noopener noreferrer" class="">@JustinBeckwith</a>!</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="nodejs" term="nodejs"/>
        <category label="featured" term="featured"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Analyzing node.js on GitHub with BigQuery]]></title>
        <id>https://jbeckwith.com/blog/2016/08/13/bigquery-github</id>
        <link href="https://jbeckwith.com/blog/2016/08/13/bigquery-github"/>
        <updated>2016-08-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[As someone who works on developer tooling - GitHub is the holy grail of data sets. There's just so much code out there, written by so many people, for so many reasons. I've often wished I could just clone all of the data on GitHub and analyze it. Well... now you can.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="BigQuery + GitHub awesomeness" src="https://jbeckwith.com/assets/images/head-4055f7637ef5f081646a2d19755df65b.png" width="872" height="318" class="img_ev3q"></p>
<p>As someone who works on developer tooling - GitHub is the holy grail of data sets. There's just so much code out there, written by so many people, for so many reasons. I've often wished I could just clone all of the data on GitHub, and then write scripts to process the data for various reasons:</p>
<ul>
<li class=""><em>What are the top 1k npm modules used with Node.js apps? We want to know this so we can test them with App Engine.</em></li>
</ul>
<ul>
<li class="">
<p><em>What percentage of people are defining their supported Ruby versions in .ruby-version files? What about Gemfile? Can we reliabily use that to choose a Ruby version for the user?</em></p>
</li>
<li class="">
<p><em>What's the most common way to inject configuration? Environment variables? Nconf? Etcd? Dotenv?</em></p>
</li>
</ul>
<p>For each of these, we're largely left to poke around using anecodtal observations or surveys. Having a simple way of answering these questions would be huge. Well... using the new <a href="https://cloudplatform.googleblog.com/2016/06/GitHub-on-BigQuery-analyze-all-the-open-source-code.html" target="_blank" rel="noopener noreferrer" class="">public GitHub dataset</a> with <a href="https://cloud.google.com/bigquery/" target="_blank" rel="noopener noreferrer" class="">BigQuery</a> we can.</p>
<ul>
<li class=""><a href="https://cloudplatform.googleblog.com/2016/06/GitHub-on-BigQuery-analyze-all-the-open-source-code.html" target="_blank" rel="noopener noreferrer" class="">GitHub on BigQuery: Analyze all the open source code</a></li>
</ul>
<p><a href="https://cloud.google.com/bigquery/" target="_blank" rel="noopener noreferrer" class="">BigQuery</a> is essentially a giant data warehouse that lets you store petabytes of data, originally built for internal use at Google. Usually querying over this much data requires a ton of infrastructure and an understanding of MapReduce... but BigQuery lets me <a href="https://venturebeat.com/2016/06/02/google-bigquery-gets-standard-sql-support-in-beta/" target="_blank" rel="noopener noreferrer" class="">just use SQL</a>.</p>
<p>One of the fun things BigQuery offers is a bunch of <a href="https://cloud.google.com/bigquery/public-data/" target="_blank" rel="noopener noreferrer" class="">public data sets</a>. Some of the fun sets include:</p>
<ul>
<li class=""><a href="https://cloud.google.com/bigquery/public-data/usa-names" target="_blank" rel="noopener noreferrer" class="">Names used in the US</a></li>
<li class=""><a href="https://cloud.google.com/bigquery/public-data/hacker-news" target="_blank" rel="noopener noreferrer" class="">Every post and comment on hacker news</a></li>
<li class=""><a href="https://cloud.google.com/bigquery/public-data/github" target="_blank" rel="noopener noreferrer" class="">Every commit and file on GitHub</a></li>
</ul>
<p><a href="https://twitter.com/SandeepDinesh/status/758372506126344192" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" alt="Fun with Sandeep at NodeSummit" src="https://jbeckwith.com/assets/images/tweet-90e93736172ab97a986881ece7e661fc.jpg" width="800" height="888" class="img_ev3q"></a></p>
<p>I was hanging out with with <a href="https://twitter.com/SandeepDinesh" target="_blank" rel="noopener noreferrer" class="">Sandeep Dinesh</a> at NodeSummit a few weeks ago, and we were chatting about some of the new data available in BigQuery from GitHub. We figured with a little bit of SQL ... we could learn all kinds of cool stuff.</p>
<p>To get started - first, you're going to need to visit the <a href="https://bigquery.cloud.google.com/" target="_blank" rel="noopener noreferrer" class="">BigQuery console</a>.</p>
<p><img decoding="async" loading="lazy" alt="BigQuery + GitHub awesomeness" src="https://jbeckwith.com/assets/images/bq-1395d80c215cec6ac55a90f91d9fc404.png" width="1646" height="1142" class="img_ev3q"></p>
<p>From here we can choose the dataset, and start taking a look at the schema. Now lets start asking some interesting questions!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-many-files-are-out-there-on-github">How many files are out there on GitHub<a href="https://jbeckwith.com/blog/2016/08/13/bigquery-github#how-many-files-are-out-there-on-github" class="hash-link" aria-label="Direct link to How many files are out there on GitHub" title="Direct link to How many files are out there on GitHub" translate="no">​</a></h2>
<p>We just need to query over the github_repos.files table, and get a count.</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">COUNT</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">bigquery</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">data</span><span class="token plain">:github_repos</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">files</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<p><code>2,122,805,654</code></p>
<p>Wow -over 2 billion files. Next question!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-many-packagejsons-are-there-on-github">How many package.json(s) are there on GitHub?<a href="https://jbeckwith.com/blog/2016/08/13/bigquery-github#how-many-packagejsons-are-there-on-github" class="hash-link" aria-label="Direct link to How many package.json(s) are there on GitHub?" title="Direct link to How many package.json(s) are there on GitHub?" translate="no">​</a></h3>
<p>This time we're just going to limit our files to paths ending in <code>package.json</code>. We can just use the <code>RIGHT</code> function to grab the end of the full path:</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">COUNT</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">bigquery</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">data</span><span class="token plain">:github_repos</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">files</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">WHERE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">RIGHT</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">12</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"package.json"</span><br></div></code></pre></div></div>
<p><code>8,128,298</code></p>
<p>Over 8 million! Now of course - this could include any project that has a <code>package.json</code> (not node.js), so it's probably going to be a little front-end heavy.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-the-most-popular-top-level-npm-import-on-github">What's the most popular top level npm import on GitHub?<a href="https://jbeckwith.com/blog/2016/08/13/bigquery-github#whats-the-most-popular-top-level-npm-import-on-github" class="hash-link" aria-label="Direct link to What's the most popular top level npm import on GitHub?" title="Direct link to What's the most popular top level npm import on GitHub?" translate="no">​</a></h3>
<p>So here's the big one. Lets say you want to know which npm module is most likely to be imported as a top level dependency? You could get some of this data by looking at <a href="https://www.npmjs.com/" target="_blank" rel="noopener noreferrer" class="">npmjs.com</a>, but that's going to include subdependencies, and also count every install. I don't want every install - I want to know how many apps are using which modules.</p>
<p>Up until this point, we've only been looking at the data available to us directly in the table. But in this case - we want to parse the <em>contents</em> of a file. This is where things start to get fun. This query will...</p>
<ul>
<li class="">Grab all of the <code>package.json</code> files out there</li>
<li class="">Get the contents of those files</li>
<li class="">Run a JavaScript user-defined-function</li>
<li class="">Place the results in a temp table</li>
<li class="">Do a <code>GROUP BY</code> / <code>ORDER BY</code> to get our final count</li>
</ul>
<p>Let's take a look!</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">COUNT</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> cnt</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> package</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  JS</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> content </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">bigquery</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">data</span><span class="token plain">:github_repos</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">contents</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">WHERE</span><span class="token plain"> id </span><span class="token operator" style="color:#393A34">IN</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> id </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">bigquery</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">public</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">data</span><span class="token plain">:github_repos</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">files</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">WHERE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">RIGHT</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">path</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">12</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"package.json"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    content</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"[{ name: 'package', type: 'string'}]"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token string" style="color:#e3116c">"function(row, emit) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">      try {</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">        x = JSON.parse(row.content);</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">        if (x.dependencies) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">          Object.keys(x.dependencies).forEach(function(dep) {</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">            emit({ package: dep });</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">          });</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">        }</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">      } catch (e) {}</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">    }"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">GROUP</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">BY</span><span class="token plain"> package</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">ORDER</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">BY</span><span class="token plain"> cnt </span><span class="token keyword" style="color:#00009f">DESC</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">LIMIT</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000</span><br></div></code></pre></div></div>
<p>So this is really freaking cool. We were able to just slam a JavaScript function in the middle of the SQL query to help us process the results. You may also notice the try/catch floating around in there - turns out that not every package.json on GitHub is valid JSON!</p>
<p>So let's take a look at the results:</p>
<table><thead><tr><th>Package</th><th>Count</th></tr></thead><tbody><tr><td>express</td><td>66207</td></tr><tr><td>lodash</td><td>55698</td></tr><tr><td>debug</td><td>47499</td></tr><tr><td>async</td><td>40054</td></tr><tr><td>inherits</td><td>35782</td></tr><tr><td>body-parser</td><td>35644</td></tr><tr><td>request</td><td>31242</td></tr><tr><td>mkdirp</td><td>25941</td></tr><tr><td>chalk</td><td>25904</td></tr><tr><td>readable-stream</td><td>25015</td></tr><tr><td>glob</td><td>24497</td></tr><tr><td>underscore</td><td>24151</td></tr><tr><td>morgan</td><td>22398</td></tr><tr><td>minimatch</td><td>20561</td></tr><tr><td>cookie-parser</td><td>19957</td></tr><tr><td>react</td><td>19764</td></tr><tr><td>through2</td><td>18488</td></tr><tr><td>mongoose</td><td>17992</td></tr><tr><td>commander</td><td>17805</td></tr><tr><td>jade</td><td>17666</td></tr><tr><td>isarray</td><td>16677</td></tr><tr><td>minimist</td><td>16518</td></tr><tr><td>socket.io</td><td>15675</td></tr><tr><td>moment</td><td>15434</td></tr><tr><td>graceful-fs</td><td>15198</td></tr><tr><td>qs</td><td>14663</td></tr><tr><td>object-assign</td><td>14218</td></tr><tr><td>jquery</td><td>13709</td></tr><tr><td>serve-favicon</td><td>13641</td></tr><tr><td>string_decoder</td><td>13597</td></tr><tr><td>source-map</td><td>13548</td></tr><tr><td>babel-runtime</td><td>13524</td></tr><tr><td>rimraf</td><td>13233</td></tr><tr><td>gulp-util</td><td>13055</td></tr><tr><td>express-session</td><td>13045</td></tr><tr><td>core-util-is</td><td>13041</td></tr><tr><td>bluebird</td><td>12751</td></tr><tr><td>semver</td><td>12722</td></tr><tr><td>passport</td><td>12530</td></tr><tr><td>q</td><td>11990</td></tr><tr><td>colors</td><td>11710</td></tr><tr><td>mime</td><td>11627</td></tr><tr><td>react-dom</td><td>11560</td></tr><tr><td>ejs</td><td>11392</td></tr><tr><td>xtend</td><td>11312</td></tr><tr><td>node-uuid</td><td>11265</td></tr><tr><td>optimist</td><td>11070</td></tr><tr><td>gulp</td><td>10934</td></tr><tr><td>compression</td><td>10759</td></tr><tr><td>once</td><td>10544</td></tr><tr><td>mime-types</td><td>10352</td></tr></tbody></table>
<p>( ... it keeps going for a while ) At the end of this - we processed quite a bit of data.</p>
<p><code>Query complete (209.3s elapsed, 1.76 TB processed)</code></p>
<p>What other types of questions should we ask? I can think of a few that may be interesting:</p>
<ul>
<li class="">Which npm dependencies are the most likely to be out of date?</li>
<li class="">How many people are using the <code>fs</code> npm module (the one on npmjs.com, not the core module)</li>
<li class="">How many people are hard coding keys in their JavaScript files?</li>
</ul>
<p>If you want to play around with the GitHub dataset, check out the <a href="https://cloud.google.com/bigquery/quickstart-web-ui" target="_blank" rel="noopener noreferrer" class="">getting started tutorial</a>.</p>
<p>If you find the answers to these (or anything else interesting), let me know at <a href="https://twitter.com/JustinBeckwith" target="_blank" rel="noopener noreferrer" class="">@JustinBeckwith</a>!</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="featured" term="featured"/>
        <category label="nodejs" term="nodejs"/>
        <category label="google" term="google"/>
        <category label="bigquery" term="bigquery"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building node.js applications on Google Cloud Platform]]></title>
        <id>https://jbeckwith.com/blog/2016/05/24/nodejs-gcp-next</id>
        <link href="https://jbeckwith.com/blog/2016/05/24/nodejs-gcp-next"/>
        <updated>2016-05-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[In March I had the chance to talk at <a href="https://cloudplatformonline.com/" target="_blank">GCP Next</a> on <a href="https://cloud.google.com/nodejs" target="_blank">Node.js @ Google</a>. This is a fun little tour of what Google Cloud has to offer Node.js developers.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Node.js is for hats and cats" src="https://jbeckwith.com/assets/images/nodejs-gcp-next-featured-0bcc65cade905dd1effe0f8c64e7fc4c.jpg" width="930" height="542" class="img_ev3q"></p>
<p>In March I had the chance to talk at <a href="https://cloudplatformonline.com/" target="_blank" rel="noopener noreferrer" class="">GCP Next</a> on <a href="https://cloud.google.com/nodejs" target="_blank" rel="noopener noreferrer" class="">Node.js @ Google</a>. This is a fun little tour of what Google Cloud has to offer Node.js developers.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="timeline">Timeline<a href="https://jbeckwith.com/blog/2016/05/24/nodejs-gcp-next#timeline" class="hash-link" aria-label="Direct link to Timeline" title="Direct link to Timeline" translate="no">​</a></h2>
<ul>
<li class=""><strong>00:00</strong> - Intro</li>
<li class=""><strong>01:57</strong> - Why Node.js</li>
<li class=""><strong>02:57</strong> - Node.js + Google Cloud Platform</li>
<li class=""><strong>03:48</strong> - The many engines of Google Cloud</li>
<li class=""><strong>04:48</strong> - Getting started with App Engine</li>
<li class=""><strong>07:26</strong> - Traffic splitting</li>
<li class=""><strong>11:45</strong> - Cloud Shell</li>
<li class=""><strong>16:03</strong> - Google Cloud APIs &amp; Services</li>
<li class=""><strong>17:03</strong> - gcloud npm module</li>
<li class=""><strong>20:17</strong> - Cloud cats demo</li>
<li class=""><strong>22:09</strong> - Code review</li>
<li class=""><strong>25:24</strong> - Cloud Debugger</li>
<li class=""><strong>27:30</strong> - Cloud Trace</li>
<li class=""><strong>28:47</strong> - Enterprise Node.js at NodeSource</li>
<li class=""><strong>37:05</strong> - Node.js and IoT</li>
<li class=""><strong>41:09</strong> - Hatspin</li>
<li class=""><strong>42:31</strong> - Closing</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="watch-the-video">Watch the video<a href="https://jbeckwith.com/blog/2016/05/24/nodejs-gcp-next#watch-the-video" class="hash-link" aria-label="Direct link to Watch the video" title="Direct link to Watch the video" translate="no">​</a></h3>
<div class="embed-container"><iframe title="Building node.js applications on GCP" width="560" height="315" src="https://www.youtube.com/embed/jsznS0QxtYI" frameborder="0"></iframe></div>
<p>Thanks!</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="featured" term="featured"/>
        <category label="nodejs" term="nodejs"/>
        <category label="google" term="google"/>
        <category label="app-engine" term="app-engine"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Dependency management and Go]]></title>
        <id>https://jbeckwith.com/blog/2015/05/29/dependency-management-go</id>
        <link href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go"/>
        <updated>2015-05-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Most programming languages have a story for dependency management. Go does as well. Sort of. The differences between the dependency management story of node.js | .net | ruby | python is interesting.]]></summary>
        <content type="html"><![CDATA[<p>I find dependency management and package managers interesting. Each language has its own package manager, and each one has characteristics that are specific to that community. NuGet for .NET has great tooling and Visual Studio support, since that's important to the .NET developer audience. NPM has a super flexible model, and great command line tools.</p>
<p>In a lot of ways, golang is a little <a href="https://golang.org/doc/faq#Why_doesnt_Go_have_feature_X" target="_blank" rel="noopener noreferrer" class="">quirky</a>. And that's awesome. However - I've really struggled to wrap my head around dependency management in Go.</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;Dependency management and golang&amp;quot;" src="https://jbeckwith.com/assets/images/package-4e641fe778f78550a874eeefc80b1c83.png" width="320" height="276" class="img_ev3q"></p>
<p>When dealing with dependency management, I expect a few things:</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-repeatable-builds">1. Repeatable builds<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#1-repeatable-builds" class="hash-link" aria-label="Direct link to 1. Repeatable builds" title="Direct link to 1. Repeatable builds" translate="no">​</a></h2>
<p>Given the same source code, I expect to be able to reproduce the same set of binaries. Every. Time. Every bit of information needed to complete a build, whether it be on my local dev box or on a build server, should be explicitly called out in my source code. No surprises.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-isolated-environments">2. Isolated environments<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#2-isolated-environments" class="hash-link" aria-label="Direct link to 2. Isolated environments" title="Direct link to 2. Isolated environments" translate="no">​</a></h2>
<p>I am likely to be working on multiple projects at a time. Each project may have a requirement on different compilers, and different versions of the same dependency. At no point should changing a dependency in one project have an effect on the dependencies on a completely separate project.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-consensus">3. Consensus<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#3-consensus" class="hash-link" aria-label="Direct link to 3. Consensus" title="Direct link to 3. Consensus" translate="no">​</a></h2>
<p>Having a package management story is awesome. What's even better is making sure everyone uses the same one :) As long as developers are inventive and curious, there will always be alternatives. But there needs to be consensus on the community accepted standard on how a package manager will work. If 5 projects use 5 different models of dependency management, we're all out of luck.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-nodejs-does-it">How node.js does it<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#how-nodejs-does-it" class="hash-link" aria-label="Direct link to How node.js does it" title="Direct link to How node.js does it" translate="no">​</a></h2>
<p><a href="http://jbeckwith.com/2015/01/04/comparing-go-and-dotnet/" target="_blank" rel="noopener noreferrer" class="">As I've talked about before</a>, I like to use my experience with other languages as a way to learn about a new language (just like most people I'd assume). Let's take a look at how NPM for node.js solves these problems.</p>
<p>Similar to the <code>go get</code> command, there is an <code>npm install</code> command. It looks like this:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">npm install --save yelp</span><br></div></code></pre></div></div>
<p>The big difference you'll see is <code>--save</code>. This tells NPM to save the dependency, and the version I'm using into the <code>package.json</code> for my project:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"pollster"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"version"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2.0.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"private"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"scripts"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"start"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"node server"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"dependencies"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"express"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"~3.1.0"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"nconf"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"~0.6.7"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"socket.io"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"~0.9.13"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p><code>package.json</code> is stored in the top level directory of my app. It provides my <code>isolation</code>. If I start another project - that means another project.json, another set of dependencies. The environments are entirely isolated. The list of dependencies and their versions provides my <code>repeatability</code>. Every time someone clones my repository and runs <code>npm install</code>, they will get the same list of dependencies from a centralized source. The fact that most people use NPM provides my <code>consensus</code>.</p>
<p>Version pinning is accomplished using <a href="http://semver.org/" target="_blank" rel="noopener noreferrer" class="">semver</a>. The <code>~</code> relaxes the rules on version matching, meaning I'm ok with bringing down a different version of my dependency, as long as it is only a <code>PATCH</code> - which means no API breaking changes, only bug fixes. If you're being super picky (on production stuff I am), you can specify a specific version minus the <code>~</code>. For downstream dependencies (dependencies of your dependencies) you can lock those in as well using <a href="https://docs.npmjs.com/cli/shrinkwrap" target="_blank" rel="noopener noreferrer" class="">npm-shrinkwrap</a>. On one of my <a href="http://azure.microsoft.com/en-us/marketplace/partners/microsoft/nodejsstartersite/" target="_blank" rel="noopener noreferrer" class="">projects</a>, I got bit by the lack of shrink-wrapping when a misbehaved package author used a wildcard import for a downstream dependency that actually broke us in production.</p>
<p>The typical workflow is to check in your <code>package.json</code>, and then .gitignore your <code>node_modules</code> directory that contains the actual source code of 3rd party packages.</p>
<p>It's all pretty awesome.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="go-out-of-the-box">Go out of the box<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#go-out-of-the-box" class="hash-link" aria-label="Direct link to Go out of the box" title="Direct link to Go out of the box" translate="no">​</a></h2>
<p>With the out of the box behavior, Go is less than ideal in repeatability, isolation, and consensus. If you follow the setup guide for golang, you'll find yourself with a single directory where you're supposed to keep all of your code. Inside of there, you create a /src directory, and a new directory for each project you're going to work on. When you install a dependency using <code>go get</code>, it will essentially drop the source code from that repository into `$GOPATH/src'. In your source code, you just tell the compiler where it needs to go to grab the latest sources:</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"github.com/JustinBeckwith/go-yelp/yelp"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">client </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> yelp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">New</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">options</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> client</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">DoSimpleSearch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"coffee"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"seattle"</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>So this is <em>really</em> bad. The <a href="https://github.com/JustinBeckwith/go-yelp" target="_blank" rel="noopener noreferrer" class="">go-yelp</a> library I'm importing from github is pulled down at compile time (if not already available from a <code>go get</code> command), and built into my project. That is pointing to the <em>master</em> branch of my github repository. Who's to say I won't change my API tomorrow, breaking everyone who has imported the library in this way? As a library author, I'm left with 3 options:</p>
<ol>
<li class="">Never make breaking changes.</li>
<li class="">Make a completely new repository on GitHub for a new version of my API that has breaking changes.</li>
<li class="">Make breaking changes, and assume / hope developers are using a dependency management tool.</li>
</ol>
<p>Without using an external tool (or one of the methods I'll talk about below), there is no concept of version pinning in go. You point towards a namespace, and that path is used to find your code during the build. For most open source projects - the out of the box behavior is broken.</p>
<p>My problem is that the default workflow on a go project leads you down a path of sadness. You start with a magical <code>go get</code> command that installs the latest and greatest version of a dependency - but doesn't ask you which specific version or hash of that dependency you should be using. Most web developers have been conditioned to not check our dependencies into source control, if they're managed by a package manager (see: gem, NuGet, NPM, bower, etc). The end result is that I could easily break someone else, and I can easily be broken.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="vendoring-import-rewrites-and-the-gopath">Vendoring, import rewrites, and the GOPATH<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#vendoring-import-rewrites-and-the-gopath" class="hash-link" aria-label="Direct link to Vendoring, import rewrites, and the GOPATH" title="Direct link to Vendoring, import rewrites, and the GOPATH" translate="no">​</a></h2>
<p>There is currently no agreed upon package manager for Go. Recently the Go team kicked up <a href="https://groups.google.com/forum/#!msg/golang-dev/nMWoEAG55v8/iJGgur7W_SEJ" target="_blank" rel="noopener noreferrer" class="">a great thread</a> asking the community for their thoughts on a package management system. There are a few high level concepts that are helpful to understand.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="vendoring">Vendoring<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#vendoring" class="hash-link" aria-label="Direct link to Vendoring" title="Direct link to Vendoring" translate="no">​</a></h3>
<p>At Google, the source code for a dependency is copied into the source tree, and checked into source control. This provides <code>repeatability</code>. There is never a question on where the source is downloaded from, because it is always available in the source tree. Copying the source from a dependency into your own source is referred to as "vendoring".</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="import-rewriting">Import rewriting<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#import-rewriting" class="hash-link" aria-label="Direct link to Import rewriting" title="Direct link to Import rewriting" translate="no">​</a></h3>
<p>After you copy the code into your source tree, you need to change your import path to not point at the original source, but rather to point at a path in your tree. This is called "Import rewriting".</p>
<p>After copying a library into your tree, instead of this:</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"github.com/JustinBeckwith/go-yelp/yelp"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">client </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> yelp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">New</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">options</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>you would do this:</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"yourtree/third_party/github.com/JustinBeckwith/go-yelp/yelp"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">client </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> yelp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">New</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">options</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="gopath-rewriting">GOPATH rewriting<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#gopath-rewriting" class="hash-link" aria-label="Direct link to GOPATH rewriting" title="Direct link to GOPATH rewriting" translate="no">​</a></h3>
<p>Vendoring and import rewriting provide our repeatable builds. But what about isolation? If project (x) relies on go-yelp#v1.0, project (y) should be able to rely on go-yelp#v2.0. They should be isolated. If you follow <a href="https://golang.org/doc/code.html" target="_blank" rel="noopener noreferrer" class="">How to write go code</a>, you're led down a path of a single workspace, which is driven by <code>$GOPATH</code>. <code>$GOPATH</code> is where libraries installed via <code>go get</code> will be installed. It controls where your own binaries are generated. It's generally the defining variable for the root of your workspace. If you try to run multiple projects out of the same directory - it completely blows up <code>isolation</code>. If you want to be able to reference different versions of the same dependency, you need to change the $GOPATH variable for each current project. The act of changing the $GOPATH environment variable when switching projects is "GOPATH rewriting".</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="package-managers--tools">Package managers &amp; tools<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#package-managers--tools" class="hash-link" aria-label="Direct link to Package managers &amp; tools" title="Direct link to Package managers &amp; tools" translate="no">​</a></h2>
<p>Given the lack of prescriptive guidance and tools on how to deal with dependency management, just a few tools have popped up. In no particular order, here are a few I found:</p>
<ul>
<li class=""><a href="https://github.com/tools/godep" target="_blank" rel="noopener noreferrer" class="">https://github.com/tools/godep</a></li>
<li class=""><a href="https://github.com/gpmgo/gopm" target="_blank" rel="noopener noreferrer" class="">https://github.com/gpmgo/gopm</a></li>
<li class=""><a href="https://github.com/pote/gpm" target="_blank" rel="noopener noreferrer" class="">https://github.com/pote/gpm</a></li>
<li class=""><a href="https://github.com/nitrous-io/goop" target="_blank" rel="noopener noreferrer" class="">https://github.com/nitrous-io/goop</a></li>
<li class=""><a href="https://github.com/alouche/rodent" target="_blank" rel="noopener noreferrer" class="">https://github.com/alouche/rodent</a></li>
<li class=""><a href="https://github.com/jingweno/nut" target="_blank" rel="noopener noreferrer" class="">https://github.com/jingweno/nut</a></li>
<li class=""><a href="https://github.com/niemeyer/gopkg" target="_blank" rel="noopener noreferrer" class="">https://github.com/niemeyer/gopkg</a></li>
<li class=""><a href="https://github.com/mjibson/party" target="_blank" rel="noopener noreferrer" class="">https://github.com/mjibson/party</a></li>
<li class=""><a href="https://github.com/kardianos/vendor" target="_blank" rel="noopener noreferrer" class="">https://github.com/kardianos/vendor</a></li>
<li class=""><a href="https://github.com/kisielk/vendorize" target="_blank" rel="noopener noreferrer" class="">https://github.com/kisielk/vendorize</a></li>
<li class=""><a href="https://github.com/mattn/gom" target="_blank" rel="noopener noreferrer" class="">https://github.com/mattn/gom</a></li>
<li class=""><a href="https://github.com/dkulchenko/bunch" target="_blank" rel="noopener noreferrer" class="">https://github.com/dkulchenko/bunch</a></li>
<li class=""><a href="https://github.com/skelterjohn/wgo" target="_blank" rel="noopener noreferrer" class="">https://github.com/skelterjohn/wgo</a></li>
<li class=""><a href="https://github.com/Masterminds/glide" target="_blank" rel="noopener noreferrer" class="">https://github.com/Masterminds/glide</a></li>
<li class=""><a href="https://github.com/robfig/glock" target="_blank" rel="noopener noreferrer" class="">https://github.com/robfig/glock</a></li>
<li class=""><a href="https://bitbucket.org/vegansk/gobs" target="_blank" rel="noopener noreferrer" class="">https://bitbucket.org/vegansk/gobs</a></li>
<li class=""><a href="https://launchpad.net/godeps" target="_blank" rel="noopener noreferrer" class="">https://launchpad.net/godeps</a></li>
<li class=""><a href="https://github.com/d2fn/gopack" target="_blank" rel="noopener noreferrer" class="">https://github.com/d2fn/gopack</a></li>
<li class=""><a href="https://github.com/laher/gopin" target="_blank" rel="noopener noreferrer" class="">https://github.com/laher/gopin</a></li>
<li class=""><a href="https://github.com/LyricalSecurity/gigo" target="_blank" rel="noopener noreferrer" class="">https://github.com/LyricalSecurity/gigo</a></li>
<li class=""><a href="https://github.com/VividCortex/johnny-deps" target="_blank" rel="noopener noreferrer" class="">https://github.com/VividCortex/johnny-deps</a></li>
</ul>
<p>Given my big 3 requirements above, I checked out the most popular of the repos above, and settled on godep. The alternatives all fell into at least one of these traps:</p>
<ul>
<li class="">Forced rewriting the url, making it harder to manage dependency paths</li>
<li class="">Relied on a centralized service</li>
<li class="">Only works on a single platform</li>
<li class="">Doesn't provide isolation in the $GOPATH</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="godep">godep<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#godep" class="hash-link" aria-label="Direct link to godep" title="Direct link to godep" translate="no">​</a></h3>
<p><a href="https://github.com/tools/godep" target="_blank" rel="noopener noreferrer" class="">Godep</a> matched most of my requirements for a package manager, and is the most popular solution in the community. It solves the repeatability and isolation issues above. The workflow:</p>
<p>Run <code>go get</code> to install a dependency (nothing new here):</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">go get github.com/JustinBeckwith/go-yelp/yelp</span><br></div></code></pre></div></div>
<p>When you're done installing dependencies, use the <code>godep save</code> command. This will copy all of the referenced code imported into the project from the current $GOPATH into the ./Godeps directory in your project. Make sure to check this into source control.</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">godep save</span><br></div></code></pre></div></div>
<p>It also will walk the graph of dependencies and create a <code>./Godeps/Godeps.json</code> file:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token property" style="color:#36acaa">"ImportPath"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"github.com/JustinBeckwith/coffee"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token property" style="color:#36acaa">"GoVersion"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"go1.4.2"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token property" style="color:#36acaa">"Deps"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token property" style="color:#36acaa">"ImportPath"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"github.com/JustinBeckwith/go-yelp/yelp"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token property" style="color:#36acaa">"Rev"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"e0e1b550d545d9be0446ce324babcb16f09270f5"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token property" style="color:#36acaa">"ImportPath"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"github.com/JustinBeckwith/oauth"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token property" style="color:#36acaa">"Rev"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"a1577bd3870218dc30725a7cf4655e9917e3751b"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ....</span><br></div></code></pre></div></div>
<p>When it's time to build, use the godep tool instead of the standard go toolchain:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">godep go build</span><br></div></code></pre></div></div>
<p>The <code>$GOPATH</code> is automatically rewritten to use the local copy of dependencies, ensuring you have isolation for your project. This approach is great for a few reasons:</p>
<ol>
<li class=""><em>Repeatable builds</em> - When someone clones the repository and runs it, everything you need to build is present. There are no floating versions.</li>
<li class=""><em>No external repository needed for dependencies</em> - with all dependencies checked into the local repository, there's no need to worry about a centralized service. <a href="http://blog.npmjs.org/post/76918947811/registry-downtime-2014-02-16" target="_blank" rel="noopener noreferrer" class="">NPM</a> will occasionally go down, as does <a href="http://blog.nuget.org/20140403/nuget-2.8.1-april-2nd-downtime.html" target="_blank" rel="noopener noreferrer" class="">NuGet</a>.</li>
<li class=""><em>Isolated environment</em> - With $GOPATH being rewritten at build time, you have complete isolation from one project to the next.</li>
<li class=""><em>No import rewriting</em> - A few other tools operate by changing the import url from the origin repository to a rewritten local repository. This makes installing dependencies a little painful, and makes the import statement somewhat unsightly.</li>
</ol>
<p>There are a few negatives though as well:</p>
<ol>
<li class="">Not checking in your dependencies is convenient. It's a pain to check in thousands of source files I won't really edit. Without a centralized repository, this is not likely to be solved.</li>
<li class="">You need to use a wrapped toolchain with the <code>godep</code> commands. There is still no real consensus.</li>
</ol>
<p>For an example of a project that uses godep, check out <a href="https://github.com/JustinBeckwith/coffee" target="_blank" rel="noopener noreferrer" class="">coffee</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wrapping-up">Wrapping up<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#wrapping-up" class="hash-link" aria-label="Direct link to Wrapping up" title="Direct link to Wrapping up" translate="no">​</a></h2>
<p>While using godep is great - I'd really love to see consensus. It's way too easy for newcomers to fall into the trap of floating dependencies, and it's hard without much official guidance to come to any sort of consensus on the right approach. At this stage - it's really up to each team to pick what they value in their dependency management story and choose one of the (many) options out there. Until proven otherwise, I'm sticking with godep.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="great-posts-on-this-subject">Great posts on this subject<a href="https://jbeckwith.com/blog/2015/05/29/dependency-management-go#great-posts-on-this-subject" class="hash-link" aria-label="Direct link to Great posts on this subject" title="Direct link to Great posts on this subject" translate="no">​</a></h2>
<p>There have been a lot of great posts by others on this subject, check these out as well:</p>
<ul>
<li class=""><a href="https://dave.cheney.net/2013/10/10/why-i-think-go-package-management-is-important" target="_blank" rel="noopener noreferrer" class="">https://dave.cheney.net/2013/10/10/why-i-think-go-package-management-is-important</a></li>
<li class=""><a href="https://dave.cheney.net/2014/03/22/thoughts-on-go-package-management-six-months-on" target="_blank" rel="noopener noreferrer" class="">https://dave.cheney.net/2014/03/22/thoughts-on-go-package-management-six-months-on</a></li>
<li class=""><a href="https://nathany.com/go-packages/" target="_blank" rel="noopener noreferrer" class="">https://nathany.com/go-packages/</a></li>
<li class=""><a href="https://blog.gopheracademy.com/advent-2014/deps/" target="_blank" rel="noopener noreferrer" class="">https://blog.gopheracademy.com/advent-2014/deps/</a></li>
<li class=""><a href="https://blog.gopheracademy.com/advent-2014/case-against-3pl/" target="_blank" rel="noopener noreferrer" class="">https://blog.gopheracademy.com/advent-2014/case-against-3pl/</a></li>
<li class=""><a href="https://kylelemons.net/blog/2012/04/22-rx-for-go-headaches.article" target="_blank" rel="noopener noreferrer" class="">https://kylelemons.net/blog/2012/04/22-rx-for-go-headaches.article</a></li>
<li class=""><a href="https://dev.af83.com/2013/09/14/a-journey-in-golang-package-manager.html" target="_blank" rel="noopener noreferrer" class="">https://dev.af83.com/2013/09/14/a-journey-in-golang-package-manager.html</a></li>
</ul>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="go" term="go"/>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Docker, Revel, and App Engine]]></title>
        <id>https://jbeckwith.com/blog/2015/05/08/docker-revel-appengine</id>
        <link href="https://jbeckwith.com/blog/2015/05/08/docker-revel-appengine"/>
        <updated>2015-05-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Revel is an easy to use web application framework for Go. Recently I wrapped up a Revel app inside of a docker container, and published it to Google App Engine.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="&amp;quot;Revel running on Google App Engine with Docker&amp;quot;" src="https://jbeckwith.com/assets/images/revel-1fe8e6cefb7ff675749b8a1686d2cd7e.png" width="300" height="283" class="img_ev3q"></p>
<p><strong>note: I recently updated this post to make sure all of the commands still work.</strong></p>
<p>I've spent some time recently using <a href="https://jbeckwith.com/2015/01/04/comparing-go-and-dotnet/" target="_blank" rel="noopener noreferrer" class="">the Go programming language</a> for my side web projects. The Go standard libraries are minimal by design - meaning it doesn't come with a prescriptive web framework out of the box. The good news is that there are a ton of options:</p>
<ul>
<li class=""><a href="https://revel.github.io/" target="_blank" rel="noopener noreferrer" class="">Revel</a></li>
<li class=""><a href="https://github.com/gin-gonic/gin" target="_blank" rel="noopener noreferrer" class="">Gin</a></li>
<li class=""><a href="https://martini.codegangsta.io/" target="_blank" rel="noopener noreferrer" class="">Martini</a></li>
<li class=""><a href="https://beego.me/" target="_blank" rel="noopener noreferrer" class="">Beego</a></li>
<li class=""><a href="https://www.gorillatoolkit.org/" target="_blank" rel="noopener noreferrer" class="">Gorilla</a></li>
</ul>
<p>Of course, you could decide to just <a href="https://news.ycombinator.com/item?id=8772760" target="_blank" rel="noopener noreferrer" class="">not use a web framework at all</a>. Comparing these is a topic of great debate - but that topic is for another post :) I decided to try out Revel first, as it was the closest to a full featured rails-esque framework at a glance. I'll likely give all of these a shot at some point.</p>
<p>After building an app on Revel, I wanted to get a feel for deploying my app to see if it posed any unique challenges. I recently started a new gig working on <a href="https://cloud.google.com/" target="_blank" rel="noopener noreferrer" class="">Google Cloud</a>, and decided to try out <a href="https://cloud.google.com/appengine/docs" target="_blank" rel="noopener noreferrer" class="">App Engine</a>. The default runtime environment for Go in App Engine is <a href="https://cloud.google.com/appengine/docs/go/#Go_The_sandbox" target="_blank" rel="noopener noreferrer" class="">sandboxed</a>. This comes with some benefits, and a few challenges. You get a lot of stuff for free, but you also are restricted in terms of file system access, network access, and library usage. Given the restrictions, I decided to use the new <a href="https://cloud.google.com/appengine/docs/go/managed-vms/" target="_blank" rel="noopener noreferrer" class="">App Engine Flexible</a> service. App Engine Flex lets you deploy your application in a docker container, while still having access to the other App Engine features like <a href="https://cloud.google.com/appengine/features/#datastore" target="_blank" rel="noopener noreferrer" class="">datastore</a>, <a href="https://cloud.google.com/appengine/features/#logs" target="_blank" rel="noopener noreferrer" class="">logging</a>, <a href="https://cloud.google.com/appengine/features/#memcache" target="_blank" rel="noopener noreferrer" class="">caching</a>, etc. The advantage of using docker here is that I don't need to write any App Engine specific code. I can write a standard Go/Revel app, and just deploy to docker.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="starting-with-revel">Starting with Revel<a href="https://jbeckwith.com/blog/2015/05/08/docker-revel-appengine#starting-with-revel" class="hash-link" aria-label="Direct link to Starting with Revel" title="Direct link to Starting with Revel" translate="no">​</a></h2>
<p>There's a pretty great <a href="https://revel.github.io/tutorial/gettingstarted.html" target="_blank" rel="noopener noreferrer" class="">getting started tutorial for Revel</a>. After getting the libraries installed, scaffold a new app with the <a href="https://revel.github.io/tutorial/createapp.html" target="_blank" rel="noopener noreferrer" class="">revel new</a> command:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">go get github.com/revel/revel</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">go get github.com/revel/cmd/revel</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">revel new myapp</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-docker">Using Docker<a href="https://jbeckwith.com/blog/2015/05/08/docker-revel-appengine#using-docker" class="hash-link" aria-label="Direct link to Using Docker" title="Direct link to Using Docker" translate="no">​</a></h2>
<p>Before touching App Engine Flexible, the first step is to get it working with docker. It took a little time and effort, but once docker is <a href="https://docs.docker.com/installation/" target="_blank" rel="noopener noreferrer" class="">completely set up on your machine</a>, writing the docker file is straight forward.</p>
<p>Here's the docker file I'm using right now:</p>
<div class="language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Use the official go docker image built on debian.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">FROM golang:1.4.2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Grab the source code and add it to the workspace.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ADD . /go/src/github.com/JustinBeckwith/revel-appengine</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Install revel and the revel CLI.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RUN go get github.com/revel/revel</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RUN go get github.com/revel/cmd/revel</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Use the revel CLI to start up our application.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ENTRYPOINT revel run github.com/JustinBeckwith/revel-appengine dev 8080</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Open up the port where the app is running.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">EXPOSE 8080</span><br></div></code></pre></div></div>
<p>There are a few things to call out with this Dockerfile:</p>
<ol>
<li class="">
<p>I chose to use the <a href="https://registry.hub.docker.com/_/golang/" target="_blank" rel="noopener noreferrer" class="">golang docker image</a> as my base. You could replicate the steps needed to install and configure go with a base debian/ubuntu image, but I found this easier. I could have also used the <a href="https://cloud.google.com/appengine/docs/managed-vms/custom-runtimes#base_images" target="_blank" rel="noopener noreferrer" class="">pre-configured App ngine golang image</a>, but I did not need the additional service account support.</p>
</li>
<li class="">
<p>The <code>ENTRYPOINT</code> command tells Docker (and App Engine) which process to run when the container is started. I'm using the CLI included with revel.</p>
</li>
<li class="">
<p>For the <code>ENTRYPOINT</code> and <code>EXPOSE</code> directives, make sure to use port 8080 - this is a hard coded port for App Engine.</p>
</li>
</ol>
<p>To start using docker with your existing revel app, you need to <a href="https://docs.docker.com/installation/" target="_blank" rel="noopener noreferrer" class="">install docker</a> and copy the <a href="https://github.com/JustinBeckwith/revel-appengine/blob/master/Dockerfile" target="_blank" rel="noopener noreferrer" class="">dockerfile</a> into the root of your app. Update the dockerfile to change the path in the <code>ADD</code> and <code>ENTRYPOINT</code> instructions to use the local path to your revel app instead of mine.</p>
<p>After you have docker setup, build your image and try running the app:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># build and run the image</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker build -t revel-appengine .</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">docker run -it -p 8080:8080 revel-appengine</span><br></div></code></pre></div></div>
<p>This will run docker, build the image locally, and then run it. Try hitting <a href="http://localhost:8080/" target="_blank" rel="noopener noreferrer" class=""><code>http://localhost:8080</code></a> in your browser. You should see the revel startup page:</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;Running revel in docker&amp;quot;" src="https://jbeckwith.com/assets/images/docker-84d8c1d7e8735c03c5c749ba89c00a1a.png" width="1024" height="373" class="img_ev3q"></p>
<p>Now we're running revel inside of docker.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="app-engine-flexible">App Engine Flexible<a href="https://jbeckwith.com/blog/2015/05/08/docker-revel-appengine#app-engine-flexible" class="hash-link" aria-label="Direct link to App Engine Flexible" title="Direct link to App Engine Flexible" translate="no">​</a></h2>
<p>The original version of App Engine had a bit of a funny way of managing application runtimes. There are a limited set of stacks available, and you're left using a locked down version an approved runtime. Flex gets rid of this restriction by letting you run pretty much anything inside of a container. You just need to define a little bit of extra config in a <code>app.yaml</code> file that tells App Engine how to treat your container:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">runtime</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> custom</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">vm</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">api_version</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> go1</span><br></div></code></pre></div></div>
<p>This config lets me use App Engine, with a custom docker image as my runtime, running on a managed virtual machine. You can copy my <a href="https://github.com/JustinBeckwith/revel-appengine/blob/master/app.yaml" target="_blank" rel="noopener noreferrer" class="">app.yaml</a> into your app directory, alongside the <a href="https://github.com/JustinBeckwith/revel-appengine/blob/master/Dockerfile" target="_blank" rel="noopener noreferrer" class="">Dockerfile</a>. Next, make sure you've signed up for a <a href="https://cloud.google.com/" target="_blank" rel="noopener noreferrer" class="">Google Cloud</a> account, and download the <a href="https://cloud.google.com/sdk/" target="_blank" rel="noopener noreferrer" class="">Google Cloud SDK</a>. After getting all of that setup, you'll need to create a new project in the <a href="https://console.developers.google.com/" target="_blank" rel="noopener noreferrer" class="">developer console</a>.</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Install the Google Cloud SDK</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">curl https://sdk.cloud.google.com | bash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Log into your account</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gcloud init</span><br></div></code></pre></div></div>
<p>That covers the initial setup. After you have a project created, you can try deploying the app. This is essentially going to startup your app using the Dockerfile we defined earlier on Google Cloud:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># Deploy the application</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">gcloud app deploy</span><br></div></code></pre></div></div>
<p>After deploying, you can visit your site here:
<a href="https://revel-gae.appspot.com/" target="_blank" rel="noopener noreferrer" class="">https://revel-gae.appspot.com</a></p>
<p><img decoding="async" loading="lazy" alt="Revel running on App Engine" src="https://jbeckwith.com/assets/images/appengine-17041ab3fd5e7e796001c803a5016374.png" width="614" height="237" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wrapping-up">Wrapping up<a href="https://jbeckwith.com/blog/2015/05/08/docker-revel-appengine#wrapping-up" class="hash-link" aria-label="Direct link to Wrapping up" title="Direct link to Wrapping up" translate="no">​</a></h2>
<p>So that's it. I decided to use revel for this one, but the whole idea behind using docker for App Engine is that you can bring pretty much any stack. If you have any questions, feel free to <a href="https://github.com/JustinBeckwith/revel-appengine" target="_blank" rel="noopener noreferrer" class="">check out the source</a>, or find me <a href="https://twitter.com/JustinBeckwith" target="_blank" rel="noopener noreferrer" class="">@JustinBeckwith</a>.</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="app-engine" term="app-engine"/>
        <category label="google" term="google"/>
        <category label="go" term="go"/>
        <category label="docker" term="docker"/>
        <category label="revel" term="revel"/>
        <category label="google-cloud" term="google-cloud"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Realtime services with io.js, redis and Azure]]></title>
        <id>https://jbeckwith.com/blog/2015/02/15/iojs-redis-azure</id>
        <link href="https://jbeckwith.com/blog/2015/02/15/iojs-redis-azure"/>
        <updated>2015-02-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A few years ago, I put together a fun little app that used node.js, service bus, cloud services, and the Instagram realtime API to build a realtime visualization of images posted to Instagram. In 2 years time, a lot has changed on the Azure platform. I decided to go back into that code, and retool it to take advantage of some new technology and platform features. And for fun.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://wazstagram.azurewebsites.net/" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" alt="&amp;quot;View the demo&amp;quot;" src="https://jbeckwith.com/assets/images/waz-screenshot-4e1e97b1c6ee31e56cba323d1d9e2df4.png" width="985" height="332" class="img_ev3q"></a></p>
<p>A few years ago, I put together a <a href="https://jbeckwith.com/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure/" target="_blank" rel="noopener noreferrer" class="">fun little app</a> that used node.js, service bus, cloud services, and the Instagram realtime API to build a realtime visualization of images posted to Instagram. In 2 years time, a lot has changed on the Azure platform. I decided to go back into that code, and retool it to take advantage of some new technology and platform features. And for fun.</p>
<ul>
<li class=""><a href="https://jbeckwith.com/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure/" target="_blank" rel="noopener noreferrer" class="">Original blog post</a></li>
<li class=""><a href="https://wazstagram.azurewebsites.net/" target="_blank" rel="noopener noreferrer" class="">View the demo on Azure</a></li>
<li class=""><a href="https://github.com/JustinBeckwith/wazstagram" target="_blank" rel="noopener noreferrer" class="">View the code on GitHub</a></li>
</ul>
<p>Let's take a look through the updates!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="resource-groups">Resource groups<a href="https://jbeckwith.com/blog/2015/02/15/iojs-redis-azure#resource-groups" class="hash-link" aria-label="Direct link to Resource groups" title="Direct link to Resource groups" translate="no">​</a></h2>
<p>I'm using <a href="http://azure.microsoft.com/en-us/documentation/articles/azure-preview-portal-using-resource-groups/" target="_blank" rel="noopener noreferrer" class="">resource groups</a> to organize the various services. Resource groups provide a nice way to visualize and manage the services that make up an app. RBAC and aggregated monitoring are two of the biggest features that make this useful.</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;Using a resource group makes it easier to organize services&amp;quot;" src="https://jbeckwith.com/assets/images/resource-group-f364b52a254959317a103e0540377c4e.png" width="1172" height="504" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="websites--websockets">Websites &amp; Websockets<a href="https://jbeckwith.com/blog/2015/02/15/iojs-redis-azure#websites--websockets" class="hash-link" aria-label="Direct link to Websites &amp; Websockets" title="Direct link to Websites &amp; Websockets" translate="no">​</a></h2>
<p>In the original version of this app, I chose to use <a href="http://azure.microsoft.com/en-us/services/cloud-services/" target="_blank" rel="noopener noreferrer" class="">cloud services</a> instead of <a href="http://azure.microsoft.com/en-us/documentation/services/websites/" target="_blank" rel="noopener noreferrer" class="">Azure web sites</a>. One of the biggest reasons for this choice was websocket support with socket.io. At the time, Azure websites did not support websockets. Well... now it does. There are a lot of reasons to choose websites over cloud services:</p>
<ul>
<li class="">Fast continuous deployment via Github</li>
<li class="">Low concept count, no special tooling needed</li>
<li class="">Now supports deployment slots, ssl, enterprise features</li>
</ul>
<p>When you create your site, make sure to turn on websockets:</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;setting up websockets&amp;quot;" src="https://jbeckwith.com/assets/images/websockets-b821fd65447554a8b9412f6ba7b539f2.png" width="905" height="523" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="iojs">io.js<a href="https://jbeckwith.com/blog/2015/02/15/iojs-redis-azure#iojs" class="hash-link" aria-label="Direct link to io.js" title="Direct link to io.js" translate="no">​</a></h2>
<p><a href="https://iojs.org/" target="_blank" rel="noopener noreferrer" class="">io.js</a> is a fork of <a href="http://nodejs.org/" target="_blank" rel="noopener noreferrer" class="">node.js</a> that provides a faster release cycle and es6 support. It's pretty easy to get it running on Azure, thanks to <a href="https://github.com/felixrieseberg/iojs-azure" target="_blank" rel="noopener noreferrer" class="">iojs-azure</a>. Just to prove I'm running io.js instead of node.js, I added this little bit in my server.js:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token template-string string" style="color:#e3116c">Started wazstagram running on </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">process</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation property-access">title</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string string" style="color:#e3116c"> </span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token template-string interpolation">process</span><span class="token template-string interpolation punctuation" style="color:#393A34">.</span><span class="token template-string interpolation property-access">version</span><span class="token template-string interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token template-string template-punctuation string" style="color:#e3116c">`</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>The results:</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;Console says it&amp;#39;s io.js&amp;quot;" src="https://jbeckwith.com/assets/images/iojs-2a446b9e87919b7ddc96ea16cbf28996.png" width="817" height="135" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="redis">redis<a href="https://jbeckwith.com/blog/2015/02/15/iojs-redis-azure#redis" class="hash-link" aria-label="Direct link to redis" title="Direct link to redis" translate="no">​</a></h2>
<p>In the previous version of this app, I used service bus for publishing messages from the back end process to the scaled out front end nodes. This worked great, but I'm more comfortable with redis. There are a lot of options for redis on Azure, but we recently rolled out a first class redis cache service, so I decided to give that a try. I'm really looking to use two features from redis:</p>
<ul>
<li class="">Pub / Sub - Messages received by Instagram are published to the scaled out front end</li>
<li class="">Caching - I keep a cache of 100 messages around to auto-fill the page on the initial visit</li>
</ul>
<p>You can create a new redis cache from the Gallery:</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;Create a new redis cache&amp;quot;" src="https://jbeckwith.com/assets/images/redis-create-fc7583c2cdb7e220d06702d7a01552e0.png" width="1845" height="852" class="img_ev3q"></p>
<p>After creating the cache, you have a good ol standard redis database. Nothing special/fancy/funky. You can connect to it using the standard redis-cli from the command line:</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;I can connect using standard redis tools&amp;quot;" src="https://jbeckwith.com/assets/images/redis-cli-0361a8bde95e40b01c155ecdafb06872.png" width="936" height="174" class="img_ev3q"></p>
<p>Note the password I'm using is actually one of the management keys provided in the portal. I also chose to disable SSL, as nothing I'm storing is sensitive data:</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;Set up non-SSL connections&amp;quot;" src="https://jbeckwith.com/assets/images/redis-ssl-faadcbd3f19291a409635785cf904008.png" width="907" height="484" class="img_ev3q"></p>
<p>I used <a href="https://github.com/mranney/node_redis" target="_blank" rel="noopener noreferrer" class="">node-redis</a> to talk to the database, both for pub/sub and cache. First, create a new redis client:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createRedisClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> redis</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">6379</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> nconf</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'redisHost'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">auth_pass</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> nconf</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'redisKey'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">return_buffers</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'error'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'ERR:REDIS: '</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// create redis clients for the publisher and the subscriber</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> redisSubClient </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createRedisClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> redisPubClient </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createRedisClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p><strong>PROTIP</strong>: Use <a href="https://github.com/flatiron/nconf" target="_blank" rel="noopener noreferrer" class="">nconf</a> to store secrets in json locally, and read from <a href="http://azure.microsoft.com/blog/2013/07/17/windows-azure-web-sites-how-application-strings-and-connection-strings-work/" target="_blank" rel="noopener noreferrer" class="">app settings</a> in Azure.</p>
<p>When the Instagram API sends a new image, it's published to a channel, and centrally cached:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">verbose</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'new pic published from: '</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">verbose</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pic</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">redisPubClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">publish</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'pics'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">stringify</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// cache results to ensure users get an initial blast of (n) images per city</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">redisPubClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">lpush</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pic</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">redisPubClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">ltrim</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">redisPubClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">lpush</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">universe</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pic</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">redisPubClient</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">ltrim</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">universe</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>The centralized cache is great, since I don't need to use up memory in each io.js process used in my site (keep scale out in mind). Each client also connects to the pub/sub channel, ensuring every instance gets new messages:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// listen to new images from redis pub/sub</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">redisSubClient</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'message'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">channel</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">verbose</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'channel: '</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> channel </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">' ; message: '</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> m </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">parse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toString</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    io</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">sockets</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">in</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">emit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'newPic'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pic</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    io</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">sockets</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">in</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">universe</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">emit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'newPic'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> m</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pic</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">subscribe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'pics'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>After setting up the service, I was using the redis-cli to do a lot of debugging. There's also some great monitoring/metrics/alerts available in the portal:</p>
<p><img decoding="async" loading="lazy" alt="&amp;quot;monitoring and metrics&amp;quot;" src="https://jbeckwith.com/assets/images/redis-mon-e283f406fd15a42e430b1d9a387e3d26.png" width="1177" height="920" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wrapping-up">Wrapping up<a href="https://jbeckwith.com/blog/2015/02/15/iojs-redis-azure#wrapping-up" class="hash-link" aria-label="Direct link to Wrapping up" title="Direct link to Wrapping up" translate="no">​</a></h2>
<p>If you have any questions, feel free to <a href="http://github.com/JustinBeckwith/wazstagram" target="_blank" rel="noopener noreferrer" class="">check out the source</a>, or find me <a href="https://twitter.com/JustinBeckwith" target="_blank" rel="noopener noreferrer" class="">@JustinBeckwith</a>.</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="azure" term="azure"/>
        <category label="featured" term="featured"/>
        <category label="microsoft" term="microsoft"/>
        <category label="node" term="node"/>
        <category label="iojs" term="iojs"/>
        <category label="redis" term="redis"/>
        <category label="socketio" term="socketio"/>
        <category label="portal" term="portal"/>
        <category label="azure" term="azure"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Please take this personally]]></title>
        <id>https://jbeckwith.com/blog/2015/02/01/please-take-this-personally</id>
        <link href="https://jbeckwith.com/blog/2015/02/01/please-take-this-personally"/>
        <updated>2015-02-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A few weeks ago I got pulled into a meeting. There's another team at Microsoft that's using our SDK to build their UI, and they had a few questions. Their devs had a chance to get their hands on our SDK, and like most product guys, I was interested in getting some unfiltered feedback from an internal team. Before getting into details, someone dropped the phrase "Please don't take this personally, but..."]]></summary>
        <content type="html"><![CDATA[<p>A few weeks ago I got pulled into a meeting. There's another team at Microsoft that's using our SDK to build their UI, and they had a few questions. Their devs had a chance to get their hands on our SDK, and like most product guys, I was interested in getting some unfiltered feedback from an internal team. Before getting into details, someone dropped the phrase <strong>"Please don't take this personally, but..."</strong></p>
<p>The feedback that comes after that sentence is really important. We write it down. We share it with the team. We stack it up against other priorities, compare it with feedback from teams who have similar pain points, and use it to find a way to make our product better. Customer feedback (from an internal team or external customer) is so incredibly critical, that any product team has a similar pattern/process for dealing with it. So what's the problem?</p>
<p>Any feedback that starts with <strong>"Don't take this personally"</strong> really pisses me off. When you say this to someone, you're making one of two judgments about this person:</p>
<ol>
<li class="">
<p><em>They are not personally invested in their work.</em> They go to their job, they do whatever work is put in front of them, and then they go home. If what they've made is not good, it doesn't bother them.</p>
</li>
<li class="">
<p>They are personally invested in their work. They want to create something amazing, and will go to great lengths to do so. Whatever you're about to say - despite your warning - <em>They're going to take it personally.</em></p>
</li>
</ol>
<p>For me, that expression elicits a sort of Marty Mcfly "nobody calls me chicken" response.</p>
<div class="embed-container"><iframe title="Nobody calls me chicken" src="https://www.youtube.com/embed/gKosmXx1gkc?start=26" frameborder="0"></iframe></div>
<p>What's more personal to me than my product!? I work at Microsoft because I genuinely believe it's the best place for me to build stuff that has a real tangible impact. I went through years of school so I could do *<strong>this</strong>*. I moved my family moved across the country. I work 50-60 hours a week (probably more than I should) because I wanted to build *<strong>this</strong>*. My product is in many ways a reflection of me. What could possibly be more personal?</p>
<p>Does this mean I don't want criticism? Of course I do! Objective criticism from an informed customer who has used your product is the greatest gift a product manager can receive. It's how we get better. Just expect me to take it personally.</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="product-management" term="product-management"/>
        <category label="featured" term="featured"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Comparing Go and .NET]]></title>
        <id>https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet</id>
        <link href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet"/>
        <updated>2015-01-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I like to use the holiday break as a time to hang out with the family, disconnect from work, and learn about something new. I've been writing a lot of JavaScript lately, so I wanted to try something different. I decided to check out golang. I found myself wanting to understand Go in terms of what I already know about .NET and nodejs, and wishing there was a guide to bridge those gaps. My goal is to make it easier for those coming from a .NET background to understand Go, and get a feel for how it relates to similar concepts in the .NET world.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="&amp;quot;The gopher image is Creative Commons Attributions 3.0 licensed. Credit Renee French.&amp;quot;" src="https://jbeckwith.com/assets/images/gopher-59ca34c7dfc637bd9fbfe80c579369e0.png" title="The gopher image is Creative Commons Attributions 3.0 licensed. Credit Renee French." width="430" height="290" class="img_ev3q"></p>
<p>2014 was a crazy year. I spent most of the year thinking about client side code while working on <a class="" href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works">the new Azure Portal</a>. I like to use the holiday break as a time to hang out with the family, disconnect from work, and learn about something new. I figured a programming language used for distributed systems was about as far from client side JavaScript as I could get for a few weeks, so I decided to check out <a href="https://golang.org/" target="_blank" rel="noopener noreferrer" class="">golang</a>.</p>
<p>Coming at this from 0 - I used a few resources to get started:</p>
<ul>
<li class=""><a href="https://tour.golang.org/welcome/1" target="_blank" rel="noopener noreferrer" class="">Tour of Go</a> - this was a great getting started guide that walks step by step through the language.</li>
<li class=""><a href="https://gobyexample.com/" target="_blank" rel="noopener noreferrer" class="">Go by Example</a> - I actually learned more from go by example than the tour. It was great.</li>
<li class=""><a href="https://github.com/google/go-github" target="_blank" rel="noopener noreferrer" class="">The github API wrapper in Go</a> - I figured I should start with some practical code samples written by folks at Google. When in doubt, I used this to make sure I was doing things 'the go way'.</li>
</ul>
<p>I'm a learn-by-doing kind of guy - so I decided to learn by building something I've built in the past - an API wrapper for the Yelp API. A few years ago, I was working with the ineffable <a href="https://twitter.com/howard_dierking" target="_blank" rel="noopener noreferrer" class="">Howard Dierking</a> on a side project to compare RoR to ASP.NET. The project we picked needed to work with the Yelp API - and we noticed the lack of a NuGet package that fit the bill (for the record, there was a gem). To get that project kickstarted, I wrote a C# wrapper over the Yelp API - so I figure, why not do the same for Go? You can see the results of these projects here:</p>
<ul>
<li class=""><a href="https://github.com/JustinBeckwith/YelpSharp" target="_blank" rel="noopener noreferrer" class="">YelpSharp</a> - C# / .NET Yelp wrapper API</li>
<li class=""><a href="https://github.com/JustinBeckwith/go-yelp" target="_blank" rel="noopener noreferrer" class="">go-yelp</a> - Go Yelp wrapper API</li>
</ul>
<p>To get a feel for the differences, it's useful to poke around the two repositories and compare apples to apples. This isn't a "Why I'm rage quitting .NET and moving to Go" post, or a "Why Go sucks and is doing it wrong" post. Each stack has it's strengths and weaknesses. Each is better suited for different teams, projects and development cultures. I found myself wanting to understand Go in terms of what I already know about .NET and nodejs, and wishing there was a guide to bridge those gaps. So I guess my goal is to make it easier for those coming from a .NET background to understand Go, and get a feel for how it relates to similar concepts in the .NET world. Here we go!</p>
<p><em><strong>disclaimer:</strong> I've been writing C# for 14 years, and Go for 14 days. Please take all judgments of Go with a grain of salt.</em></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="environment-setup">Environment Setup<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#environment-setup" class="hash-link" aria-label="Direct link to Environment Setup" title="Direct link to Environment Setup" translate="no">​</a></h2>
<p>In the .NET world, after you install Visual Studio - you're really free to set up a project wherever you like. By default, projects are created in ~/Documents, but that's just a default. When we need to reference another project - you create a project reference in Visual Studio, or you can install a NuGet package. Either way - there really aren't any restrictions on where the project lives.</p>
<p>Go takes a different approach. If you're getting started, it's really important to read/follow this guide:</p>
<p><a href="https://golang.org/doc/code.html" target="_blank" rel="noopener noreferrer" class="">How to write go code</a></p>
<p>All go code you write goes into a single root directory, which has a directory for each project / namespace. You tell the go tool chain where to find that directory via the $GOPATH environment variable. You can see on my box, I have all of the pieces I've written or played around with here:</p>
<p><img decoding="async" loading="lazy" alt="$GOPATH" src="https://jbeckwith.com/assets/images/gopath-137170089dbea66b7de375493df7ed9f.png" width="1033" height="244" class="img_ev3q"></p>
<p>For a single $GOPATH, you have one set of dependencies, and you keep a single version of the go toolchain. It felt a little uncomfortable, and at times it made me think of the <a href="http://msdn.microsoft.com/en-us/library/yf1d93sz%28v=vs.110%29.aspx" target="_blank" rel="noopener noreferrer" class="">GAC</a>. It's also pretty similar to Ruby. Ruby has <a href="https://github.com/wayneeseguin/rvm" target="_blank" rel="noopener noreferrer" class="">RVM</a> to solve this problem, and Go has <a href="https://github.com/moovweb/gvm" target="_blank" rel="noopener noreferrer" class="">GVM</a>. If you're working on different Go projects that have different requirements for runtime version / dependencies - I'd imagine you want to use GVM. Today, I only have one project - so it is less of a concern.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="build--runtime">Build &amp; Runtime<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#build--runtime" class="hash-link" aria-label="Direct link to Build &amp; Runtime" title="Direct link to Build &amp; Runtime" translate="no">​</a></h3>
<p>In .NET land we use msbuild for compilation. On my team we use Visual Studio at dev time, and run msbuild via jenkins on our CI server. This is a pretty typical setup. At compile time, C# code is compiled down into IL, which is then just-in-time compiled at runtime to the native assembly language of the system's host.</p>
<p>Go is a little different, as it compiles directly to native code on the current platform. If I compile my yelp library in OSX, it creates an executable that will run on my current machine. This binary is not interpreted, or IL - it is a good ol' native executable. When linking occurs, the full native go runtime is embedded in your binary. It has much more of a c++ / gcc kind of feel. I'm sure this doesn't hurt in the performance department - which is one of the reasons folks move from Python/Ruby/Node to Go.</p>
<p>Compilation of <em>.go files is done by running the <code>go build</code> command from within the directory that contains your go files. I haven't really come across many projects using complex builds - its usually sufficient to just use <code>go build</code>. Outside of that - it seems like most folks are using <a href="http://blog.snowfrog.net/2013/06/18/golang-building-with-makefile-and-jenkins/" target="_blank" rel="noopener noreferrer" class="">makefiles to perform build automation</a>. There's really no equivalent of a</em>.csproj file, or <em>.sln file in go - so there's no baked in file you would run through an msbuild equivalent. There are just</em>.go files in a directory, that you run the build tool against. At first I found all of this alarming. After a while - I realized that it mostly "just worked". It feels very similar to the csproj-less build system of <a href="http://jbeckwith.com/2014/11/09/aspnet-vnext-oredev/" target="_blank" rel="noopener noreferrer" class="">ASP.NET vNext</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="package-management">Package management<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#package-management" class="hash-link" aria-label="Direct link to Package management" title="Direct link to Package management" translate="no">​</a></h3>
<p>In the .NET world, package management is pretty well known: it's all about <a href="http://nuget.org/" target="_blank" rel="noopener noreferrer" class="">NuGet</a>. You create a project it, add a nuspec, compile a nupkg with binaries, and publish them to <a href="http://nuget.org/" target="_blank" rel="noopener noreferrer" class="">nuget.org</a>. There are a lot of NuGet packages that fall under the "must have" category - things like <a href="http://www.nuget.org/packages/Newtonsoft.Json/" target="_blank" rel="noopener noreferrer" class="">JSON.NET</a>, <a href="http://www.nuget.org/packages/elmah/" target="_blank" rel="noopener noreferrer" class="">ELMAH</a> and even <a href="http://www.nuget.org/packages/Microsoft.AspNet.Mvc/6.0.0-beta1" target="_blank" rel="noopener noreferrer" class="">ASP.NET MVC</a>. It's not uncommon to have 30+ packages referenced in your project.</p>
<p>In .NET, we have a <code>packages.config</code> that contains a list of dependencies. This is nice, because it explicitly lays out what we depend upon, and the specific version we want to use:</p>
<div class="language-xml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-xml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">packages</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">package</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">Newtonsoft.Json</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">version</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">4.5.11</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">targetFramework</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">net40</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">package</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">RestSharp</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">version</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">104.1</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">targetFramework</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">net40</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">packages</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></div></code></pre></div></div>
<p>Go takes a bit of a different approach. The general philosophy of Go seems to trend towards avoiding external dependencies. I've found Blake Mizerany's talk to be pretty standard for sentiment from the community:</p>
<div class="embed-container"><iframe title="Three fallacies of dependencies" src="http://www.youtube.com/embed/yi5A3cK1LNA" frameborder="0"></iframe></div>
<p>In Go - there's no equivalent of <code>packages.config</code>. It just doesn't exist. Instead - dependency installation is driven from Git/Hg repositories or local paths. The dependency is installed into your go path with the <code>go get</code> command:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">go get github.com/JustinBeckwith/go-yelp/yelp</span><br></div></code></pre></div></div>
<p>This command pulls down the relevant sources from the Git/Hg repository, and builds the binaries specific to your OS. To use the dependency, you don't reference a namespace or dll - you just import the library using the same url used to acquire the library:</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"github.com/JustinBeckwith/go-yelp/yelp"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">client </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> yelp</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">New</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">options</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> client</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">DoSimpleSearch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"coffee"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"seattle"</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>When you <code>go compile</code>, the compiler walks through each *.go file, finds the list of external (non BCL) libraries, and implicitly does a <code>go get</code> if needed. This is both awesome and frightening at the same time. It's great that go doesn't require explicit dependencies. It's great that I don't need to think of the package and the namespace as different entities. It's <strong>not</strong> cool that I cannot choose a specific version of a package. No wonder the go community is skeptical of external dependencies - I wouldn't reference the tip of the master branch of any project and expect it to keep working for the long haul.</p>
<p>To get get around this limitation, a few package managers started to pop up in the community. <a href="https://code.google.com/p/go-wiki/wiki/PackageManagementTools" target="_blank" rel="noopener noreferrer" class="">There are a lot of them.</a> Given the lack of a single winner in this space, I chose to write my package 'the go way' and not attempt using a package manager.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="tooling">Tooling<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#tooling" class="hash-link" aria-label="Direct link to Tooling" title="Direct link to Tooling" translate="no">​</a></h3>
<p>In the .NET world - <a href="http://msdn.microsoft.com/en-us/vstudio/aa718325.aspx" target="_blank" rel="noopener noreferrer" class="">Visual Studio</a> is king. I know a lot of folks that use things like JetBrains or SublimeText for code editing (I'm one of those SublimeText folks), but really it's all about VS. Visual Studio gives us project templates, IntelliSense, builds, tests, refactoring, code outlines - you get it. It's all in the box. A giant box.</p>
<p>With Go, most developers tend to use a more stripped down code editor. There are a lot of folks using vim, sublimetext, or notepad++. Here are some of the more popular options:</p>
<ul>
<li class=""><a href="https://github.com/DisposaBoy/GoSublime" target="_blank" rel="noopener noreferrer" class="">GoSublime</a></li>
<li class=""><a href="https://github.com/fatih/vim-go" target="_blank" rel="noopener noreferrer" class="">vim-go</a></li>
<li class=""><a href="https://github.com/visualfc/liteide" target="_blank" rel="noopener noreferrer" class="">LiteIDE</a></li>
</ul>
<p>You can find a good conversation about the topic <a href="http://www.reddit.com/r/golang/comments/2739gp/golang_ides/" target="_blank" rel="noopener noreferrer" class="">on this reddit thread</a>. Personally - I'm comfortable with SublimeText, so I went with that + the GoSublime plugin. It gave me syntax highlighting, auto-format on save, and some lightweight IntelliSense for core packages. That having been said, <a href="https://github.com/visualfc/liteide" target="_blank" rel="noopener noreferrer" class="">LiteIDE</a> feels a little more close to a full featured IDE:</p>
<p><img decoding="async" loading="lazy" alt="LiteIDE" src="https://jbeckwith.com/assets/images/liteide-b2a1b182e68270b8c0bbf7d00d5aee12.png" width="794" height="615" class="img_ev3q"></p>
<p>There are a lot of options out there - which is a good thing :) Go comes with a variety of other command line tools that make working with the framework easier:</p>
<ul>
<li class=""><em>go build</em> - builds your code</li>
<li class=""><em>go install</em> - builds the code, and installs it in the $GOPATH</li>
<li class=""><em>go test</em> - runs all tests in the project</li>
<li class=""><em>gofmt</em> - formats your source code matching go coding standards</li>
<li class=""><em>gocov</em> - perform code coverage analysis</li>
</ul>
<p>I used all of these while working on my library.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="testing">Testing<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#testing" class="hash-link" aria-label="Direct link to Testing" title="Direct link to Testing" translate="no">​</a></h3>
<p>In <a href="https://github.com/JustinBeckwith/YelpSharp" target="_blank" rel="noopener noreferrer" class="">YelpSharp</a>, I have the typical unit test project included with my package. I have several test files created, each of which has several test functions. I can then run my test through Visual Studio or the test runner. A typical test would look like this:</p>
<div class="language-cs codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cs codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">[</span><span class="token attribute class-name">TestMethod</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">VerifyGeneralOptions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> y </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">Yelp</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Options</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> searchOptions </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">SearchOptions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    searchOptions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">GeneralOptions </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">GeneralOptions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        term </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"coffee"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    searchOptions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">LocationOptions </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token constructor-invocation class-name">LocationOptions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        location </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"seattle"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> results </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> y</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Search</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">searchOptions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Result</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Assert</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">IsTrue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">businesses </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Assert</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">IsTrue</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">results</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">businesses</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Count </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>The accepted pattern in Go for tests is to write a corresponding <code>&lt;filename&gt;_test.go</code> for each Go file. Every method that starts with <code>Test&lt;RestOfFunctionName&gt;</code> in the name, is executed as part of the test suite. By running <code>go test</code>, you run every test in the current project. It's pretty convenient, though I found myself wishing for something that auto-compiled my code and auto-ran tests (similar to the grunt/mocha/concurrent setup I like to use in node). A typical test function in go would look like this:</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// TestGeneralOptions will verify search with location and search term.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">TestGeneralOptions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">testing</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">T</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> client </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> options </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> SearchOptions</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  GeneralOptions</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">GeneralOptions</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   Term</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"coffee"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  LocationOptions</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">LocationOptions</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   Location</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"seattle"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> client</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">DoSearch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">options</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">check</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">assert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">t</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">len</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Businesses</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> containsResults</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>The assert I used here is not baked in - there are <a href="http://golang.org/doc/faq#assertions" target="_blank" rel="noopener noreferrer" class="">no asserts in Go</a>. For code coverage reports, the <code>gocov</code> tool does a nice job. To automatically run test against my GitHub repository, and auto-generate code coverage reports - I've using <a href="https://travis-ci.org/" target="_blank" rel="noopener noreferrer" class="">Travis CI</a> and <a href="https://coveralls.io/" target="_blank" rel="noopener noreferrer" class="">Coveralls.io</a>. I'm planning on writing up another post on the tools you can use to build an effective open source Go library - so more on that later :)</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="programming-language">Programming language<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#programming-language" class="hash-link" aria-label="Direct link to Programming language" title="Direct link to Programming language" translate="no">​</a></h3>
<p>Finally, let's take a look at some code. C# is amazing. It's been around now for 15 years or so, and it's grown methodically (in a good way). In terms of basic syntax, it's your standard C derivative language:</p>
<div class="language-cs codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cs codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">System</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">System</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Collections</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Generic</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">System</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Linq</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">System</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Text</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">namespace</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">YelpSharp</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Data</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Options</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// options for locale</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;/summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">LocaleOptions</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">BaseOptions</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// ISO 3166-1 alpha-2 country code. Default country to use when parsing the location field.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// United States = US, Canada = CA, United Kingdom = GB (not UK).</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;/summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">string</span><span class="token plain"> cc </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">set</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// ISO 639 language code (default=en). Reviews written in the specified language will be shown.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;/summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">string</span><span class="token plain"> lang </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">set</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// format the properties for the querystring - bounds is a single querystring parameter</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;/summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">override</span><span class="token plain"> Dictionary</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">lt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">string</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">gt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">GetParameters</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token class-name keyword" style="color:#00009f">var</span><span class="token plain"> ps </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> Dictionary</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">lt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">string</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">gt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">String</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">IsNullOrEmpty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> ps</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">cc</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">String</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">IsNullOrEmpty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lang</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> ps</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">lang</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">lang</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> ps</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>C# supports both static and dynamic typing, but generally trends towards a static type style. I've always appreciated the way C# can appeal to both new and experienced developers. The best part about the language in my opinion has been the steady, thoughtful introduction of new features. Some of the things that happened between C# 1.0 and C# 5.0 (the current version) include:</p>
<ul>
<li class=""><a href="http://msdn.microsoft.com/en-us/library/hh191443.aspx" target="_blank" rel="noopener noreferrer" class="">Async / Await</a></li>
<li class=""><a href="http://msdn.microsoft.com/en-us/library/512aeb7t.aspx" target="_blank" rel="noopener noreferrer" class="">LINQ</a></li>
<li class=""><a href="http://msdn.microsoft.com/en-us/library/wa80x488.aspx" target="_blank" rel="noopener noreferrer" class="">Partial Classes &amp; Methods</a></li>
<li class=""><a href="http://msdn.microsoft.com/en-us/library/dscyy5s0.aspx" target="_blank" rel="noopener noreferrer" class="">Iterators</a></li>
<li class=""><a href="http://msdn.microsoft.com/en-us/library/bb384062.aspx" target="_blank" rel="noopener noreferrer" class="">Object initializers</a></li>
<li class=""><a href="http://msdn.microsoft.com/en-us/library/dd264739.aspx" target="_blank" rel="noopener noreferrer" class="">Optional paramters</a></li>
<li class=""><a href="http://msdn.microsoft.com/en-us/library/bb384061.aspx" target="_blank" rel="noopener noreferrer" class="">Variable type inference</a></li>
<li class=""><a href="http://msdn.microsoft.com/en-us/library/bb383977.aspx" target="_blank" rel="noopener noreferrer" class="">Extension methods</a></li>
<li class=""><a href="http://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx" target="_blank" rel="noopener noreferrer" class="">Nullable Types</a></li>
<li class="">many things I'm forgetting...</li>
</ul>
<p>There's more great stuff coming in <a href="http://msdn.microsoft.com/en-us/magazine/dn802602.aspx" target="_blank" rel="noopener noreferrer" class="">C# 6.0</a>.</p>
<p>With Go - I found most language features to be... well... missing. It's a really basic language - you get interfaces (not the way we know them), maps, slices, arrays, and some primitives. It's very minimal - and this is by design. I was surprised when I started using go and found a few things missing (in no order):</p>
<ul>
<li class="">Generics</li>
<li class="">Exception handling</li>
<li class="">Method overloading</li>
<li class="">Optional parameters</li>
<li class="">Nullable types</li>
<li class="">Implementing an interface explicitly</li>
<li class="">foreach, while, yield, etc</li>
</ul>
<p>To understand why Go doesn't have these features - you have to understand the roots of the language. Rob Pike (one of the designers of Go) really explains the problems they were trying to solve, and the design decisions of the language well in his post <a href="http://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html" target="_blank" rel="noopener noreferrer" class="">"Less is exponentially more"</a>. The idea is to provide a set of base primitive constructs: only the ones that are absolutely required.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="interfaces-methods-and-not-classes">Interfaces, methods, and not-classes<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#interfaces-methods-and-not-classes" class="hash-link" aria-label="Direct link to Interfaces, methods, and not-classes" title="Direct link to Interfaces, methods, and not-classes" translate="no">​</a></h4>
<p>Having written a lot of C# - I got used to having all of these features at my disposal. I got used to traditional OOP features like classes, inheritance, method overloading, and explicit interfaces. I also write a lot of JavaScript - so I understand (and love) dynamic typing. What's weird about Go is that is both statically typed - and doesn't provide many of the OOP features I've grown to lean upon.</p>
<p>To see how this plays out - lets look at the same structure written in Go:</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">package</span><span class="token plain"> yelp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// LocaleOptions provide additional search options that enable returning results</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// based on a given country or locale.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> LocaleOptions </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// ISO 3166-1 alpha-2 country code. Default country to use when parsing the location field.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// United States = US, Canada = CA, United Kingdom = GB (not UK).</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> cc   </span><span class="token builtin">string</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// ISO 639 language code (default=en). Reviews written in the specified language will be shown.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> lang </span><span class="token builtin">string</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// getParameters will reflect over the values of the given struct, and provide a type appropriate</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// set of querystring parameters that match the defined values.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">o </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">LocaleOptions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getParameters</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">params </span><span class="token keyword" style="color:#00009f">map</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> params </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">make</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">map</span><span class="token punctuation" style="color:#393A34">[</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cc </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  params</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"cc"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">cc</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">lang </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">""</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  params</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"lang"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> o</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">lang</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> params</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>There are a few interesting things to call out from these two samples:</p>
<ul>
<li class="">The Go sample and C# are close to the same size - XMLDoc in this case really makes C# seem longer.</li>
<li class="">I'm not using a class - but rather an interface. Interfaces can support methods via the syntax above. If you define a func that takes a pointer to an object of the interface type - it now supports methods.</li>
<li class="">In my C# sample, this structure implements an interface. In Go, you write an interface, and then structures implement them ambiently - there is no <code>implements</code> keyword.</li>
<li class="">Pointers are an important concept in Go. I haven't had to think about pointers since 2001 (the last time I wrote C++). It's not a big deal, but not something I expected to run into.</li>
<li class="">Notice that the <code>getParameters()</code> function returns multiple results - that's new (and kind of cool).</li>
<li class="">The <code>getParameters()</code> method returns an error as one of the potential return values. You need to do that since <em>there is no concept of an exception in Go</em>.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="error-handling">Error handling<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#error-handling" class="hash-link" aria-label="Direct link to Error handling" title="Direct link to Error handling" translate="no">​</a></h4>
<p>Let that one sink for a moment. Go takes a strange (but effective) approach to error handling. Instead of tossing an exception and expecting the caller to catch and react, many (if not most) functions will return an error. It's on the caller to check the value of that error, and choose how to react. You can learn more about <a href="http://blog.golang.org/error-handling-and-go" target="_blank" rel="noopener noreferrer" class="">error handling in Go here</a>. The net result, is that I wrote a lot of code like this:</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// DoSearch performs a complex search with full search options.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">client </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">Client</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">DoSearch</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">options SearchOptions</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">result SearchResult</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// get the options from the search provider</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> params</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> options</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getParameters</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> SearchResult</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// perform the search request</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> rawResult</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> client</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">makeRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">searchArea</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> params</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> SearchResult</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// convert the result from json</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> err </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> json</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Unmarshal</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">rawResult</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">amp</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">result</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> SearchResult</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> result</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>In this example, the <code>DoSearch</code> method returns multiple values (get used to this), one of which is an error. There are 3 different method calls made in this function - all of which may return an error. For each of them, you need to check the err value, and choose how to react - oftentimes, just bubbling the error back up through the callstack by hand. I haven't quite learned to love this aspect of the language yet.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="writing-async-code">Writing async code<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#writing-async-code" class="hash-link" aria-label="Direct link to Writing async code" title="Direct link to Writing async code" translate="no">​</a></h4>
<p>In the previous sample, you may have noticed something fishy. On the following line, I'm making an HTTP request, checking for an error, and them moving forward:</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">rawResult</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">_</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">:=</span><span class="token plain"> client</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">makeRequest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">searchArea</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> params</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> err </span><span class="token operator" style="color:#393A34">!=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> SearchResult</span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">...</span><br></div></code></pre></div></div>
<p>That code is <em>synchronous</em>. When I first wrote this code - I was fairly certain I was making a mistake. Years of callbacks or promises in node, and years of tasks and async/await in C# had taught me something really clear - synchronous methods that block the thread are bad. But here's Go - just doing it's thing. I thought I was making a mistake, until I started poking around and found a <a href="http://stackoverflow.com/questions/23709118/does-golang-have-callback-concept" target="_blank" rel="noopener noreferrer" class="">few people with the same misunderstanding</a>. To make a call asynchronously in Go, it's largely up to the caller, using a <a href="https://gobyexample.com/goroutines" target="_blank" rel="noopener noreferrer" class="">goroutine</a>. Goroutines are kind of cool. You essentially point at a function and say 'run this asynchronously':</p>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Announce</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> delay time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Duration</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">go</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">func</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        time</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Sleep</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">delay</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        fmt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// Note the parentheses - must call the function.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Running <code>go &lt;func&gt;</code> in this manner will run the function concurrently in the same process. This does not create a system thread or fork the process - it's completely internal to the go runtime. Like most things with Go - I was confused and scared at first, as I tried to apply what I know about C# and JavaScript to their model. I haven't written enough of this style of asynchronous code to have a great feel for the subject, but I plan to spend a lot of time here in the coming weeks.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next<a href="https://jbeckwith.com/blog/2015/01/04/comparing-go-and-dotnet#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h3>
<p>My experience so far with Go has been at times frustrating, but certainty not boring. The best advice I can give for those new to the language is to let go of your preconceived notion of how [insert concept or task] works - it's almost like the designers of Go tried to do things differently for the sake of doing it differently at times. And that's ok :) I was cursing far less at the end of the project than the beginning, and I've now started to move towards understanding why it's different (except for the lack of generics - that's just weird). It's helping me question some of the design decisions I've made on my own APIs at work, and helped me better appreciate the niceties of C#.</p>
<p>I've really only scratched the surface of what's out there for Go. Now that I've put together a library, I'm going to take the next step and start playing around with <a href="http://revel.github.io/" target="_blank" rel="noopener noreferrer" class="">revel</a>, which provides an ASP.NET style web framework on top of Go. From there, I'm going to keep on building, and see where this goes. Happy coding!</p>
<p><em>The gopher image is Creative Commons Attributions 3.0 licensed. Credit Renee French.</em></p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="featured" term="featured"/>
        <category label="aspnet" term="aspnet"/>
        <category label="go" term="go"/>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[es6: Getting ready for the next version of JavaScript]]></title>
        <id>https://jbeckwith.com/blog/2014/11/11/es6-oredev</id>
        <link href="https://jbeckwith.com/blog/2014/11/11/es6-oredev"/>
        <updated>2014-11-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[While attending the developer conference <a href="http://oredev.org" target="_blank">Øredev</a> last week, I had the pleasure of giving a talk on <a href="http://vimeo.com/111289052" target="_blank">es6</a>. Many of the new features I covered touch on challenges we've faced building the <a href="/blog/2014/09/20/how-the-azure-portal-works/" target="_blank">Azure Portal</a>. Instead of covering each new feature one by one (<a href="https://github.com/lukehoban/es6features" target="_blank">Luke Hoban already does a nice job of that</a>) I decided to cover a few high level features that fundamentally affect the way teams build large scale JavaScript applications. I also covered the tools you can use today to use these new APIs before browsers catch up.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Rockin&amp;#39; the big stage at Øredev" src="https://jbeckwith.com/assets/images/es6-oredev-889b556d53059dc3e9224ade20f87e16.png" width="430" height="290" class="img_ev3q"></p>
<p>While attending the developer conference <a href="http://oredev.org/" target="_blank" rel="noopener noreferrer" class="">Øredev</a> last week, I had the pleasure of giving a talk on <a href="http://vimeo.com/111289052" target="_blank" rel="noopener noreferrer" class="">es6</a>. Many of the new features I covered touch on challenges we've faced building the <a class="" href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works">Azure Portal</a>. Instead of covering each new feature one by one (<a href="https://github.com/lukehoban/es6features" target="_blank" rel="noopener noreferrer" class="">Luke Hoban already does a nice job of that</a>) I decided to cover a few high level features that fundamentally affect the way teams build large scale JavaScript applications.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="timeline">Timeline<a href="https://jbeckwith.com/blog/2014/11/11/es6-oredev#timeline" class="hash-link" aria-label="Direct link to Timeline" title="Direct link to Timeline" translate="no">​</a></h2>
<ul>
<li class=""><strong>00:00</strong> - Intro</li>
<li class=""><strong>01:45</strong> - History of JavaScript</li>
<li class=""><strong>05:00</strong> - Challenges with large scale applications</li>
<li class=""><strong>08:45</strong> - Modules</li>
<li class=""><strong>13:20</strong> - Classes</li>
<li class=""><strong>15:15</strong> - Using the Traceur compiler</li>
<li class=""><strong>17:30</strong> - TypeScript &amp; AMD</li>
<li class=""><strong>20:15</strong> - Scope / What is 'this'</li>
<li class=""><strong>21:30</strong> - Arrow functions</li>
<li class=""><strong>22:30</strong> - Let vs var</li>
<li class=""><strong>25:00</strong> - Browser support</li>
<li class=""><strong>28:45</strong> - Promises</li>
<li class=""><strong>34:00</strong> - Node.js support</li>
<li class=""><strong>36:50</strong> - More features</li>
<li class=""><strong>37:13</strong> - es7</li>
<li class=""><strong>38:50</strong> - Closing</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="watch-the-video">Watch the video<a href="https://jbeckwith.com/blog/2014/11/11/es6-oredev#watch-the-video" class="hash-link" aria-label="Direct link to Watch the video" title="Direct link to Watch the video" translate="no">​</a></h3>
<div class="embed-container"><iframe title="ES6: GETTING READY FOR JAVASCRIPT VNEXT" src="//player.vimeo.com/video/111289052?portrait=0" width="750" height="450" frameborder="0"></iframe></div>
<p><a href="http://vimeo.com/111289052" target="_blank" rel="noopener noreferrer" class="">ES6: GETTING READY FOR JAVASCRIPT VNEXT</a> from <a href="http://vimeo.com/user4280938" target="_blank" rel="noopener noreferrer" class="">Øredev Conference</a> on <a href="https://vimeo.com/" target="_blank" rel="noopener noreferrer" class="">Vimeo</a>.</p>
<p>Thanks!</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="featured" term="featured"/>
        <category label="javascript" term="javascript"/>
        <category label="oredev" term="oredev"/>
        <category label="typescript" term="typescript"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building web applications with ASP.NET vNext]]></title>
        <id>https://jbeckwith.com/blog/2014/11/09/aspnet-vnext-oredev</id>
        <link href="https://jbeckwith.com/blog/2014/11/09/aspnet-vnext-oredev"/>
        <updated>2014-11-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Last week I had the amazing opportunity to give a talk on <a href="http://asp.net/vNext" target="_blank">ASP.NET vNext</a> at the <a href="http://oredev.org" target="_blank">Øredev</a> developer conference. I had a blast - especially the part where I got to show off the new bits to a few hundred people on the big stage. It's especially fun showing off the new features that open up ASP.NET development with Mono on OSX. There's a lot of great stuff in this release - the new request pipeline, bin deployable CLR, command line tools, configuration APIs, SublimeText support, fewer dependencies on Visual Studio - and lots of open source.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Rockin&amp;#39; the big stage at Øredev" src="https://jbeckwith.com/assets/images/aspnetvnext-featured-4eafe88d470e636705b4c606299f8edc.png" width="430" height="290" class="img_ev3q"></p>
<p>Last week I had the amazing opportunity to give a talk on <a href="http://asp.net/vNext" target="_blank" rel="noopener noreferrer" class="">ASP.NET vNext</a> at the <a href="http://oredev.org/" target="_blank" rel="noopener noreferrer" class="">Øredev</a> developer conference. I had a blast - especially the part where I got to show off the new bits to a few hundred people on the big stage. It's especially fun showing off the new features that open up ASP.NET development with Mono on OSX. There's a lot of great stuff in this release - the new request pipeline, bin deployable CLR, command line tools, configuration APIs, SublimeText support, fewer dependencies on Visual Studio - and lots of open source.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="timeline">Timeline<a href="https://jbeckwith.com/blog/2014/11/09/aspnet-vnext-oredev#timeline" class="hash-link" aria-label="Direct link to Timeline" title="Direct link to Timeline" translate="no">​</a></h2>
<ul>
<li class=""><strong>00:00</strong> - Intro</li>
<li class=""><strong>04:20</strong> - Challenges with the current stack</li>
<li class=""><strong>06:25</strong> - Intro to ASP.NET vNext</li>
<li class=""><strong>07:50</strong> - ASP.NET vNext project templates</li>
<li class=""><strong>10:05</strong> - Controllers, Models, Views</li>
<li class=""><strong>12:30</strong> - Reference model</li>
<li class=""><strong>14:45</strong> - project.json</li>
<li class=""><strong>16:30</strong> - Commands</li>
<li class=""><strong>18:20</strong> - KVM, KPM, &amp; K</li>
<li class=""><strong>22:45</strong> - Startup.cs</li>
<li class=""><strong>23:50</strong> - Configuration</li>
<li class=""><strong>26:15</strong> - Services</li>
<li class=""><strong>27:00</strong> - Module registration</li>
<li class=""><strong>31:00</strong> - Open source ASP.NET</li>
<li class=""><strong>34:15</strong> - Publishing with CoreCLR &amp; MVC</li>
<li class=""><strong>36:00</strong> - OSX, Mono, SublimeText</li>
<li class=""><strong>40:15</strong> - Timeline</li>
<li class=""><strong>41:30</strong> - Closing</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="watch-the-video">Watch the video<a href="https://jbeckwith.com/blog/2014/11/09/aspnet-vnext-oredev#watch-the-video" class="hash-link" aria-label="Direct link to Watch the video" title="Direct link to Watch the video" translate="no">​</a></h3>
<div class="embed-container"><iframe title="Building web applications with ASP.NET" src="//player.vimeo.com/video/111004374?portrait=0&amp;color=c9ff23" width="750" height="450" frameborder="0"></iframe></div>
<p><a href="http://vimeo.com/111004374">Building web applications with ASP.NET</a> from <a href="http://vimeo.com/user4280938">Øredev Conference</a> on <a href="https://vimeo.com/">Vimeo</a>.</p>
<p>Thanks!</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="featured" term="featured"/>
        <category label="aspnet" term="aspnet"/>
        <category label="oredev" term="oredev"/>
        <category label="aspnet" term="aspnet"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Under the hood of the new Azure Portal]]></title>
        <id>https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works</id>
        <link href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works"/>
        <updated>2014-09-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[For the last year and a half, I've been part of the team that's building the new Azure portal - and it's been quite an experience. A lot has been said about the end to end experience, the integration of Visual Studio Online, and even some of the new services that have been released lately. All of that's awesome, but it's not what I want to talk about today. As much as those things are great (and I mean, who doesn't like the design), the real interesting piece is the underlying architecture. Let's take a look under the hood of the new Azure portal.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Damn, we look good." src="https://jbeckwith.com/assets/images/portal-5d655fe3fe4e5e9ea8f2441369ce65c9.png" width="1227" height="718" class="img_ev3q"></p>
<p>So - I haven't been doing much blogging or speaking on WebMatrix or node recently. For the last year and a half, I've been part of the team that's building the new <a href="http://portal.azure.com/" target="_blank" rel="noopener noreferrer" class="">Azure portal</a> - and it's been quite an experience. A lot has been said about the <a href="http://channel9.msdn.com/Blogs/Windows-Azure/Azure-Preview-portal" target="_blank" rel="noopener noreferrer" class="">end to end experience</a>, the <a href="http://blogs.msdn.com/b/bharry/archive/2014/04/03/visual-studio-online-integration-in-the-azure-portal.aspx" target="_blank" rel="noopener noreferrer" class="">integration of Visual Studio Online</a>, and even some of the <a href="http://weblogs.asp.net/scottgu/azure-new-documentdb-nosql-service-new-search-service-new-sql-alwayson-vm-template-and-more" target="_blank" rel="noopener noreferrer" class="">new services that have been released lately</a>. All of that's awesome, but it's not what I want to talk about today. As much as those things are great (and I mean, who doesn't like the design), the real interesting piece is the underlying architecture. Let's take a look under the hood of the new Azure portal.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-little-history">A little history<a href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works#a-little-history" class="hash-link" aria-label="Direct link to A little history" title="Direct link to A little history" translate="no">​</a></h2>
<p>To understand how the new portal works, you need to know a little about the <a href="http://manage.windowsazure.com/" target="_blank" rel="noopener noreferrer" class="">current management portal</a>. When the current portal was started, there were only a handful of services in Azure. Off of the top of my head, I think they were:</p>
<ul>
<li class="">Cloud Services</li>
<li class="">Web sites</li>
<li class="">Storage</li>
<li class="">Cache</li>
<li class="">CDN</li>
</ul>
<p>Out of the gate - this was pretty easy to manage. Most of those teams were all in the same organization at Microsoft, so coordinating releases was feasible. The portal team was a single group that was responsible for delivering the majority of the UI. There was little need to hand off responsibility to the individual experiences to the teams which wrote the services, as it was easier to keep everything in house. There is a single ASP.NET MVC application, which contains all of the CSS, JavaScript, and shared widgets used throughout the app.</p>
<p><img decoding="async" loading="lazy" alt="The current Azure portal, in all of it&amp;#39;s blue glory" src="https://jbeckwith.com/assets/images/vcurrent-4f5dbbdd25f87b4c1f6e18f10edc4c83.png" width="1158" height="715" class="img_ev3q"></p>
<p>The team shipped every 3 weeks, tightly coordinating the schedule with each service team. It works ... pretty much as one would expect a web application to work.</p>
<p><strong><em>And then everything went crazy.</em></strong></p>
<p>As we started ramping up the number of services in Azure, it became infeasible for one team to write all of the UI. The teams which owned the service were now responsible (mostly) for writing their own UI, inside of the portal source repository. This had the benefit of allowing individual teams to control their own destiny. However - it now mean that we had hundreds of developers all writing code in the same repository. A change made to the SQL Server management experience could break the Azure Web Sites experience. A change to a CSS file by a developer working on virtual machines could break the experience in storage. Coordinating the 3 week ship schedule became really hard. The team was tracking dependencies across multiple organizations, the underlying REST APIs that powered the experiences, and the release cadence of ~40 teams across the company that were delivering cloud services.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="scaling-to--services">Scaling to ∞ services<a href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works#scaling-to--services" class="hash-link" aria-label="Direct link to Scaling to ∞ services" title="Direct link to Scaling to ∞ services" translate="no">​</a></h3>
<p>Given the difficulties of the engineering and ship processes with the current portal, scaling to 200 different services didn't seem like a great idea with the current infrastructure. The next time around, we took a different approach.</p>
<p>The new portal is designed like an operating system. It provides a set of UI widgets, a navigation framework, data management APIs, and other various services one would expect to find with any UI framework. The portal team is responsible for building the operating system (or the shell, as we like to call it), and for the overall health of the portal.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="sandboxing-in-the-browser">Sandboxing in the browser<a href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works#sandboxing-in-the-browser" class="hash-link" aria-label="Direct link to Sandboxing in the browser" title="Direct link to Sandboxing in the browser" translate="no">​</a></h4>
<p>To claim we're an OS, we had to build a sandboxing model. One badly behaving application shouldn't have the ability to bring down the whole OS. In addition to that - an application shouldn't be able to grab data from another, unless by an approved mechanism. JavaScript by default doesn't really lend itself well to this kind of isolation - most web developers are used to picking up something like jQuery, and directly working against the DOM. This wasn't going to work if we wanted to protect the OS against badly behaving (or even malicious) code.</p>
<p>To get around this, each new service in Azure builds what we call an 'extension'. It's pretty much an application to our operating system. It runs in isolation, inside of an IFRAME. When the portal loads, we inject some bootstrapping scripts into each IFRAME at runtime. Those scripts provide the structured API extensions use to communicate with the shell. This API includes things like:</p>
<ul>
<li class="">Defining parts, blades, and commands</li>
<li class="">Customizing the UI of parts</li>
<li class="">Binding data into UI elements</li>
<li class="">Sending notifications</li>
</ul>
<p>The most important aspect is that the extension developer doesn't get to run arbitrary JavaScript in the portal's window. They can only run script in their IFRAME - which does not project UI. If an extension starts to fault - we can shut it down before it damages the broader system. We spent some time looking into web workers - but found some reliability problems when using &gt; 20 of them at the same time. We'll probably end up back there at some point.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="distributed-continuous-deployment">Distributed continuous deployment<a href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works#distributed-continuous-deployment" class="hash-link" aria-label="Direct link to Distributed continuous deployment" title="Direct link to Distributed continuous deployment" translate="no">​</a></h4>
<p>In this model, each extension is essentially it's own web application. Each service hosts their own extension, which is pulled into the shell at runtime. The various UI services of Azure aren't composed until they are loaded in the browser. This lets us do some really cool stuff. At any given point, a separate experience in the portal (for example, Azure Websites) can choose to deploy an extension that affects only their UI - completely independent of the rest of the portal.</p>
<p><strong><em>IFRAMEs are not used to render the UI - that's all done in the core frame. The IFRAME is only used to automate the JavaScript APIs that communicate over window.postMessage().</em></strong></p>
<p><img decoding="async" loading="lazy" alt="Each extension is loaded into the shell at runtime from their own back end" src="https://jbeckwith.com/assets/images/extensions-fa04ebf48638142c2f2dc8c166299e34.png" width="1029" height="796" class="img_ev3q"></p>
<p>This architecture allows us to scale to ∞ deployments in a given day. If the media services team wants to roll out a new feature on a Tuesday, but the storage team isn't ready with updates they're planning - that's fine. They can each deploy their own changes as needed, without affecting the rest of the portal.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="stuff-were-using">Stuff we're using<a href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works#stuff-were-using" class="hash-link" aria-label="Direct link to Stuff we're using" title="Direct link to Stuff we're using" translate="no">​</a></h3>
<p>Once you start poking around, you'll notice the portal is big single page application. That came with a lot of challenges - here are some of the technologies we're using to solve them.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="typescript">TypeScript<a href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works#typescript" class="hash-link" aria-label="Direct link to TypeScript" title="Direct link to TypeScript" translate="no">​</a></h4>
<p>Like any single page app, the portal runs a lot of JavaScript. We have a ton of APIs that run internal to the shell, and APIs that are exposed for extension authors across Microsoft. To support our enormous codebase, and the many teams using our SDK to build portal experiences, we chose to use <a href="http://www.typescriptlang.org/" target="_blank" rel="noopener noreferrer" class="">TypeScript</a>.</p>
<ul>
<li class=""><strong>TypeScript compiles into JavaScript.</strong> There's no runtime VM, or plug-ins required.</li>
<li class=""><strong>The tooling is awesome.</strong> Visual Studio gives us (and partner teams) IntelliSense and compile time validation.</li>
<li class=""><strong>Generating interfaces for partners is really easy.</strong> We distribute d.ts files which partners use to program against our APIs.</li>
<li class=""><strong>There's great integration for using AMD module loading.</strong> This is critical to us for productivity and performance reasons. (more on this in another post).</li>
<li class=""><strong>JavaScript is valid TypeScript - so the learning curve isn't so high.</strong> The syntax is also largely forward looking to ES6, so we're actually getting a jump on some new concepts.</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="less">Less<a href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works#less" class="hash-link" aria-label="Direct link to Less" title="Direct link to Less" translate="no">​</a></h4>
<p>Visually, there's a lot going on inside of the portal. To help organize our CSS, and promote usability, we've adopted <a href="http://lesscss.org/" target="_blank" rel="noopener noreferrer" class="">LESS</a>. Less does a couple of cool things for us:</p>
<ul>
<li class=""><strong>We can create variables for colors.</strong> We have a pre-defined color palette - less makes it easy to define those up front, and re-use the same colors throughout our style sheets.</li>
<li class=""><strong>The tooling is awesome.</strong> Similar to TypeScript, Visual Studio has great Less support with full IntelliSense and validation.</li>
<li class=""><strong>It made theming easier.</strong></li>
</ul>
<p><img decoding="async" loading="lazy" alt="The dark theme of the portal was much easier to make using less" src="https://jbeckwith.com/assets/images/portaldark-146aaa1fc7c7288fd881e197d052a1c0.png" width="1191" height="742" class="img_ev3q"></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="knockout">Knockout<a href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works#knockout" class="hash-link" aria-label="Direct link to Knockout" title="Direct link to Knockout" translate="no">​</a></h4>
<p>With the new design, we were really going for a 'live tile' feel. As new websites are added, or new log entries are available, we wanted to make sure it was easy for developers to update that information. Given that goal, along with the quirks of our design (extension authors can't write JavaScript that runs in the main window), <a href="http://knockoutjs.com/" target="_blank" rel="noopener noreferrer" class="">Knockout</a> turned out to be a fine choice. There are a few reasons we love Knockout:</p>
<ul>
<li class=""><strong>Automatic refreshing of the UI</strong> - The data binding aspect of Knockout is pretty incredible. We make changes to underlying model objects in TypeScript, and the UI is updated for us.</li>
<li class=""><strong>The tooling is great.</strong> This is starting to be a recurring theme :) Visual Studio has some great tooling for Knockout data binding expressions (thanks <a href="http://madskristensen.net/" target="_blank" rel="noopener noreferrer" class="">Mads</a>).</li>
<li class=""><strong>The binding syntax is pure</strong> - We're not stuck putting invalid HTML in our code to support the specifics of the binding library. Everything is driven off of data-* attributes.</li>
</ul>
<p>I'm sure there are 100 other reasons our dev team could come up with on why we love Knockout. Especially the ineffable <a href="http://blog.stevensanderson.com/" target="_blank" rel="noopener noreferrer" class="">Steve Sanderson</a>, who joined our dev team to work on the project. He even gave an awesome talk on the subject at NDC:</p>
<div class="embed-container"><div style="margin-left:auto;margin-right:auto"><iframe title="Steve Sanderson - Architecting large Single Page Applications with Knockout.js" src="//player.vimeo.com/video/97519516" width="100%" height="400" frameborder="0"></iframe></div><p><a href="http://vimeo.com/97519516" target="_blank" rel="noopener noreferrer" class="">Steve Sanderson - Architecting large Single Page Applications with Knockout.js</a> from <a href="http://vimeo.com/ndcoslo" target="_blank" rel="noopener noreferrer" class="">NDC Conferences</a> on <a href="https://vimeo.com/" target="_blank" rel="noopener noreferrer" class="">Vimeo</a>.</p></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next<a href="https://jbeckwith.com/blog/2014/09/20/how-the-azure-portal-works#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h3>
<p>I'm really excited about the future of the portal. Since our first release at //build, we've been working on new features, and responding to a lot of the <a href="http://feedback.azure.com/forums/223579-azure-preview-portal" target="_blank" rel="noopener noreferrer" class="">customer feedback</a>. Either way - we really want to know what you think.</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="featured" term="featured"/>
        <category label="azure" term="azure"/>
        <category label="typescript" term="typescript"/>
        <category label="portal" term="portal"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Switching from Wordpress to Jekyll]]></title>
        <id>https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll</id>
        <link href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll"/>
        <updated>2013-07-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Over the last few weeks, I've been slowly moving my blog from Wordpress to Jekyll. The change has been a long time coming, and so far I couldn't be happier with the results. I thought it may be interesting to make the ultimate meta post, and write a blog post about my blog. You can take a look at the source code on GitHub. Jekyll takes a bit of a different approach to serving up a blog. Instead of the traditional model of hosting an active web application with PHP/Ruby/.NET/whatever and a database, you simply post static pages.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="jekyll is fun" src="https://jbeckwith.com/assets/images/jekyll-e5a66e40aec09cc57e1ae44d6a4514b7.png" width="430" height="290" class="img_ev3q"></p>
<p>Over the last few weeks, I've been slowly moving my blog from Wordpress to <a href="http://jekyllrb.com/" target="_blank" rel="noopener noreferrer" class="">Jekyll</a>. The change has been a long time coming, and so far I couldn't be happier with the results. I thought it may be interesting to make the ultimate meta post, and write a blog post about my blog. You can take a look at the <a href="https://github.com/JustinBeckwith/justinbeckwith.github.io" target="_blank" rel="noopener noreferrer" class="">source code on GitHub</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-wrong-with-wordpress">What's wrong with Wordpress?<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#whats-wrong-with-wordpress" class="hash-link" aria-label="Direct link to What's wrong with Wordpress?" title="Direct link to What's wrong with Wordpress?" translate="no">​</a></h2>
<p>In short? Absolutely nothing. I love Wordpress. I've been using it across multiple sites for years, I worked on a <a href="http://webmatrix.com/" target="_blank" rel="noopener noreferrer" class="">product that supported Wordpress development</a>, I've even blogged here about <a href="http://jbeckwith.com/2012/06/09/wordpress-and-webmatrix/" target="_blank" rel="noopener noreferrer" class="">speaking at WordCamp</a>. The problem is that for me, the costs of a full featured blog engine outweigh the benefits.</p>
<p><img decoding="async" loading="lazy" alt="Every damn time." src="https://jbeckwith.com/assets/images/update-b8ddc83e09fc536536f9f3a50a2e127c.png" width="852" height="157" class="img_ev3q"></p>
<p>Let me give you an example. My post rate on this blog is atrocious. Part of the reason is that like most people I'm freakishly busy, but there's another nagging reason - every time I sit down to write a post, I'm burdened with maintenance costs. On the few evenings I have the time or content to write a post, it would usually go like this:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">9:00 PM - Kids are in bed. Time to sit down and write that blog post.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">9:05 PM - I'm logged into the Wordpress admin site. Looks like I need an update. Better install it.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">9:15 PM - Oh, I have some permissions error when I try to download. I'll do it manually.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">9:35 PM - Alright, I backed up my database, downloaded the new Wordpress version and did a manual upgrade.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">9:40 PM - My plugins are broken. Dammit.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">9:45 PM - Updating my plugins causes another access denied error.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">9:50 PM - I had to use putty and remember the flags for chmod. F-me.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">10:00 PM - That was fun. I'm going to bed.</span><br></div></code></pre></div></div>
<p>Running a Wordpress blog comes with a cost. You need to keep it updated. You need to find the right plugins, and keep those updated. You need to back up databases. You need to have a strategy for backing up changes to the theme. For someone that's posting every week, these costs may be worth it. It just isn't worth it to me.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="enter-jekyll">Enter Jekyll<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#enter-jekyll" class="hash-link" aria-label="Direct link to Enter Jekyll" title="Direct link to Enter Jekyll" translate="no">​</a></h3>
<p>Jekyll takes a bit of a different approach to serving up a blog. Instead of the traditional model of hosting an active web application with PHP/Ruby/.NET/whatevs and a database, you simply post static pages. You write your posts in one of the supported markup languages (I use good ol' HTML), and then write the jekyll build tool to generate your static HTML pages. There are around 100 posts on setting up jekyll, <a href="http://jekyllrb.com/docs/home/" target="_blank" rel="noopener noreferrer" class="">none better than the official documentation</a> - so I won't go too deep into how jekyll works. I'll just share my setup.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="importing-wordpress">Importing Wordpress<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#importing-wordpress" class="hash-link" aria-label="Direct link to Importing Wordpress" title="Direct link to Importing Wordpress" translate="no">​</a></h4>
<p>After playing around with the <a href="http://jekyllrb.com/docs/quickstart/" target="_blank" rel="noopener noreferrer" class="">quick start guide</a>, I got started by importing the Wordpress data to script out the first version of the site. The jekyll site has a great section on <a href="http://jekyllrb.com/docs/migrations/" target="_blank" rel="noopener noreferrer" class="">migrating from other blogs</a>, so I mostly followed their steps.</p>
<p>First, I downloaded my wordpress.xml file from the Wordpress admin:</p>
<p><img decoding="async" loading="lazy" alt="export" src="https://jbeckwith.com/assets/images/export-d7a34023463a86f7e6867ab0fe75aaaa.png" width="470" height="402" class="img_ev3q"></p>
<p>Next I ran the import tool:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">gem install hpricot</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ruby -rubygems -e 'require "jekyll/jekyll-import/wordpressdotcom";</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    JekyllImport::WordpressDotCom.process({ :source =&gt; "wordpress.xml" })'</span><br></div></code></pre></div></div>
<p>This downloaded all of my existing posts, and created new posts with metadata in jekyll format (woo!). What it didn't do was download all of my images. To get around that, I just connected with my FTP client and downloaded my images directory into the root of my jekyll site.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="syntax-highlighting">Syntax Highlighting<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#syntax-highlighting" class="hash-link" aria-label="Direct link to Syntax Highlighting" title="Direct link to Syntax Highlighting" translate="no">​</a></h4>
<p>One of the plugins I had installed on my Wordpress site was <a href="http://wordpress.org/plugins/syntaxhighlighter/" target="_blank" rel="noopener noreferrer" class="">SyntaxHighlighter Evolved</a>. Jekyll comes with a built in syntax highlighting sysyntax using Pygments and Liquid:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> logger </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">winston</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Logger</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">transports</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">winston</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">transports</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Console</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">winston</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">transports</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Skywriter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">account</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> stName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> stKey</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">partition</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'os'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">hostname</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">':'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pid</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Started wazstagram backend'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>That's all well and good but - the syntax highlighter wasn't quite as nice as I would like. I also didn't feel the need to lock myself into liquid for something that can be handled on the client. I chose to use <a href="http://prismjs.com/" target="_blank" rel="noopener noreferrer" class="">PrismJS</a>, largely because I've used it in the past with success. Someone even wrote a fancy jekyll plugin to <a href="http://gmurphey.com/2012/08/09/jekyll-plugin-syntax-highlighting-with-prism.html" target="_blank" rel="noopener noreferrer" class="">generate your highlighted markup at compile time</a>, if that's your thing.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="--watch-and-livereload">--watch and livereload<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#--watch-and-livereload" class="hash-link" aria-label="Direct link to --watch and livereload" title="Direct link to --watch and livereload" translate="no">​</a></h4>
<p>As I worked on the site, I was making a lot of changes, rebuilding, waiting for the build to finish, and reloading the browser. To make some of this easier, I did a few things. Instead of saving my file, building, and running the server every time, you can just use the built in watch command:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">jekyll serve --watch</span><br></div></code></pre></div></div>
<p>This will run the server, watch for changes, and perform a build anytime something is modified on disk. The other side to this is refreshing the browser automatically. To accomplish that, I used <a href="http://livereload.com/" target="_blank" rel="noopener noreferrer" class="">LiveReload</a> with the Chrome browser plugin:</p>
<p><img decoding="async" loading="lazy" alt="LiveReload refreshes the browser after a change" src="https://jbeckwith.com/assets/images/livereload-c59500ddfcdfd48b50d008b8f95ff732.png" width="800" height="443" class="img_ev3q"></p>
<p>The OSX version of LiveReload lets you set a delay between noticing the change on the filesystem and refreshing the browser. You really want to set that to a second or two just to give jekyll enough time to compile the full site after the first change hits the disk.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="rss-feed">RSS Feed<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#rss-feed" class="hash-link" aria-label="Direct link to RSS Feed" title="Direct link to RSS Feed" translate="no">​</a></h4>
<p>One of the pieces that isn't baked into jekyll is the construction of an RSS feed. The good news is that <a href="https://github.com/snaptortoise/jekyll-rss-feeds" target="_blank" rel="noopener noreferrer" class="">someone already solved this problem</a>. This repository has a few great examples.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="archive-by-category">Archive by Category<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#archive-by-category" class="hash-link" aria-label="Direct link to Archive by Category" title="Direct link to Archive by Category" translate="no">​</a></h4>
<p>One of the pieces I wanted to add was a post archive page. Building this was relatively straight forward - you create a list of categories used across all of the posts in your site. Next you render an excerpt for each post:</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">{% raw %}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">container</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">home</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">h1</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">The Archive</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">h1</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">hrbar</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">&nbsp;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">categories</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      {% for category in site.categories %}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">span</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">a</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">href</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">#{{ category[0] }}</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">{{ category[0] }} ({{ category[1].size }})</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">a</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">span</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">span</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">dot</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">&nbsp;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">span</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      {% endfor %}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">hrbar</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">&nbsp;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">all-posts</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      {% for category in site.categories %}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">a</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">name</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">{{category[0]}}</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">a</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ### {{ category[0] }}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">ul</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">class</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">posts</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          {% for post in category[1] %}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">li</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">span</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">{{ post.date | date_to_string }}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">span</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"> »</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">a</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">href</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">{{ post.url }}</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain">{{ post.title }}</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">a</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">li</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          {% endfor %}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">ul</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      {% endfor %}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">div</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">{% endraw %}</span><br></div></code></pre></div></div>
<p>For the full example, <a href="https://github.com/JustinBeckwith/justinbeckwith.github.io/blob/master/archive.html" target="_blank" rel="noopener noreferrer" class="">check it out on GitHub</a>.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="disqus">Disqus<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#disqus" class="hash-link" aria-label="Direct link to Disqus" title="Direct link to Disqus" translate="no">​</a></h4>
<p>I used <a href="http://disqus.com/" target="_blank" rel="noopener noreferrer" class="">Disqus</a> for my commenting and discussion engine. This probably isn't news to anyone, but disqus is pretty awesome. Without a backend database to power user sign ups and comments, it's easier to just hand this over to a third party service (and it's free!). One tip though - disqus has a 'discovery' feature turned on by default. It shows a bunch of links I don't want, and muddied up the comments. Here's where you can turn it off:</p>
<p><img decoding="async" loading="lazy" alt="turn off discovery under settings-&amp;gt;discovery-&amp;gt;Just comments" src="https://jbeckwith.com/assets/images/disqus-9f97a5e8a41832445c09ec07447e4159.png" width="948" height="471" class="img_ev3q"></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="backups">Backups<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#backups" class="hash-link" aria-label="Direct link to Backups" title="Direct link to Backups" translate="no">​</a></h4>
<p>With no database, backing up means just backing up the files. Good news everyone! I'm just using good ol <a href="https://github.com/JustinBeckwith/justinbeckwith.github.io" target="_blank" rel="noopener noreferrer" class="">GitHub and a git repository</a> to track changes and store my files. I keep local files in Dropbox just in case.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="hosting-the-bits">Hosting the bits<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#hosting-the-bits" class="hash-link" aria-label="Direct link to Hosting the bits" title="Direct link to Hosting the bits" translate="no">​</a></h4>
<p>The coolest part of using Jekyll is that you can <a href="https://help.github.com/articles/using-jekyll-with-pages" target="_blank" rel="noopener noreferrer" class="">host your site on GitHub - for free</a>. They build the site when you push changes, and even let you set up a <a href="https://help.github.com/articles/setting-up-a-custom-domain-with-pages" target="_blank" rel="noopener noreferrer" class="">custom domain</a>.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's Next?<a href="https://jbeckwith.com/blog/2013/07/17/wordpress-to-jekyll#whats-next" class="hash-link" aria-label="Direct link to What's Next?" title="Direct link to What's Next?" translate="no">​</a></h4>
<p>Now that I've got the basic workflow for the site rolling (hopefully with less maintenance costs), the next piece I'll probably tackle is performance. Between Bootstrap, JQuery, and Prism I'm pushing a lot of JavaScript and CSS that should be bundled and minified. Until then, I'm just going to keep enjoying writing my posts in SublimeText and publishing with a git push. Let me know what you think!</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="featured" term="featured"/>
        <category label="meta" term="meta"/>
        <category label="jekyll" term="jekyll"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Scalable realtime services with Node.js, Socket.IO and Windows Azure]]></title>
        <id>https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure</id>
        <link href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure"/>
        <updated>2013-01-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Wazstagram is a fun experiment with node.js on Windows Azure and the Instagram Realtime API. The project uses various services in Windows Azure to create a scalable window into Instagram traffic across multiple cities. The application is written in node.js, using cloud services in Windows Azure. A scalable set of backend nodes receive messages from the Instagram Realtime API. Those messages are sent to the front end nodes using Windows Azure Service Bus. The front end nodes are running node.js with express and socket.io.]]></summary>
        <content type="html"><![CDATA[<p><a href="http://wazstagram.azurewebsites.net/" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" alt="WAZSTAGRAM" src="https://jbeckwith.com/assets/images/waz-screenshot-4e1e97b1c6ee31e56cba323d1d9e2df4.png" title="View the Demo" width="985" height="332" class="img_ev3q"></a></p>
<p><a href="http://wazstagram.azurewebsites.net/" target="_blank" rel="noopener noreferrer" class="">Wazstagram</a> is a fun experiment with node.js on <a href="http://www.windowsazure.com/en-us/develop/nodejs/" target="_blank" rel="noopener noreferrer" class="">Windows Azure</a> and the <a href="http://instagram.com/developer/realtime/" target="_blank" rel="noopener noreferrer" class="">Instagram Realtime API</a>. The project uses various services in Windows Azure to create a scalable window into Instagram traffic across multiple cities.</p>
<ul>
<li class=""><a href="http://wazstagram.azurewebsites.net/" target="_blank" rel="noopener noreferrer" class="">View the demo on Windows Azure</a></li>
<li class=""><a href="https://github.com/JustinBeckwith/wazstagram/" target="_blank" rel="noopener noreferrer" class="">View the code on GitHub</a></li>
</ul>
<p>The code I used to build <a href="https://github.com/JustinBeckwith/wazstagram/" target="_blank" rel="noopener noreferrer" class="">WAZSTAGRAM</a> is under an <a href="https://github.com/JustinBeckwith/wazstagram/blob/master/LICENSE.md" target="_blank" rel="noopener noreferrer" class="">MIT license</a>, so feel free to learn and re-use the code.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-does-it-work">How does it work<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#how-does-it-work" class="hash-link" aria-label="Direct link to How does it work" title="Direct link to How does it work" translate="no">​</a></h2>
<p>The application is written in node.js, using cloud services in Windows Azure. A scalable set of backend nodes receive messages from the Instagram Realtime API. Those messages are sent to the front end nodes using <a href="http://msdn.microsoft.com/en-us/library/hh690929.aspx" target="_blank" rel="noopener noreferrer" class="">Windows Azure Service Bus</a>. The front end nodes are running node.js with <a href="http://expressjs.com/" target="_blank" rel="noopener noreferrer" class="">express</a> and <a href="http://socket.io/" target="_blank" rel="noopener noreferrer" class="">socket.io</a>.</p>
<p><img decoding="async" loading="lazy" alt="WAZSTAGRAM Architecture" src="https://jbeckwith.com/assets/images/architecture-091525cbb929df4d95311204be8a16ae.png" title="WAZSTAGRAM Architecture" width="738" height="523" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="websites-and-virtual-machines-and-cloud-services-oh-my">Websites, and Virtual Machines, and Cloud Services, Oh My<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#websites-and-virtual-machines-and-cloud-services-oh-my" class="hash-link" aria-label="Direct link to Websites, and Virtual Machines, and Cloud Services, Oh My" title="Direct link to Websites, and Virtual Machines, and Cloud Services, Oh My" translate="no">​</a></h3>
<p>One of the first things you need to grok when using Windows Azure is the different options you have for your runtimes. Windows Azure supports three distinct models, which can be mixed and matched depending on what you're trying to accomplish:</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="websites">Websites<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#websites" class="hash-link" aria-label="Direct link to Websites" title="Direct link to Websites" translate="no">​</a></h4>
<p><a href="http://www.windowsazure.com/en-us/home/scenarios/web-sites/" target="_blank" rel="noopener noreferrer" class="">Websites</a> in Windows Azure match a traditional PaaS model, when compared to something like Heroku or AppHarbor. They work with node.js, asp.net, and php. There is a free tier. You can use git to deploy, and they offer various scaling options. For an example of a real time node.js site that works well in the Website model, check out my <a href="https://github.com/JustinBeckwith/TwitterMap" target="_blank" rel="noopener noreferrer" class="">TwitterMap</a> example. I chose not to use Websites for this project because a.) websockets are currently not supported in our Website model, and b.) I want to be able to scale my back end processes independently of the front end processes. If you don't have crazy enterprise architecture or scaling needs, Websites work great.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="virtual-machines">Virtual Machines<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#virtual-machines" class="hash-link" aria-label="Direct link to Virtual Machines" title="Direct link to Virtual Machines" translate="no">​</a></h4>
<p>The <a href="http://www.windowsazure.com/en-us/home/scenarios/virtual-machines/" target="_blank" rel="noopener noreferrer" class="">Virtual Machine</a> story in Windows Azure is pretty consistent with IaaS offerings in other clouds. You stand up a VM, you install an OS you like (yes, <a href="http://www.windowsazure.com/en-us/manage/linux/" target="_blank" rel="noopener noreferrer" class="">we support linux</a>), and you take on the management of the host. This didn't sound like a lot of fun to me because I can't be trusted to install patches on my OS, and do other maintainency things.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="cloud-services">Cloud Services<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#cloud-services" class="hash-link" aria-label="Direct link to Cloud Services" title="Direct link to Cloud Services" translate="no">​</a></h4>
<p><a href="http://www.windowsazure.com/en-us/manage/services/cloud-services/" target="_blank" rel="noopener noreferrer" class="">Cloud Services</a> in Windows Azure are kind of a different animal. They provide a full Virtual Machine that is stateless - that means you never know when the VM is going to go away, and a new one will appear in it's place. It's interesting because it means you have to architect your app to not depend on stateful system resources pretty much from the start. It's great for new apps that you're writing to be scalable. The best part is that the OS is patched automagically, so there's no OS maintenance. I chose this model because a.) we have some large scale needs, b.) we want separation of conerns with our worker nodes and web nodes, and c.) I can't be bothered to maintain my own VMs.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-started">Getting Started<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#getting-started" class="hash-link" aria-label="Direct link to Getting Started" title="Direct link to Getting Started" translate="no">​</a></h3>
<p>After picking your runtime model, the next thing you'll need is some tools. Before we move ahead, you'll need to <a href="http://www.windowsazure.com/en-us/pricing/free-trial/" target="_blank" rel="noopener noreferrer" class="">sign up for an account</a>. Next, get the command line tools. Windows Azure is a little different because we support two types of command line tools:</p>
<ul>
<li class=""><a href="http://www.windowsazure.com/en-us/develop/nodejs/how-to-guides/powershell-cmdlets/" target="_blank" rel="noopener noreferrer" class="">PowerShell Cmdlets</a>: these are great if you're on Windows and dig the PowerShell thing.</li>
<li class=""><a href="http://www.windowsazure.com/en-us/manage/linux/other-resources/command-line-tools/" target="_blank" rel="noopener noreferrer" class="">X-Platform CLI</a>: this tool is interesting because it's written in node, and is available as a node module. You can actually just <code>npm install -g azure-cli</code> and start using this right away. It looks awesome, though I wish they had kept the flames that were in the first version.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="X-Plat CLI" src="https://jbeckwith.com/assets/images/cli-7be624c239a21706abdf8ea9ba9575ca.png" title="X-Plat CLI" width="813" height="491" class="img_ev3q"></p>
<p>For this project, I chose to use the PowerShell cmdlets. I went down this path because the Cloud Services stuff is not currently supported by the X-Platform CLI (I'm hoping this changes). If you're on MacOS and want to use Cloud Services, you should check out <a href="https://github.com/tjanczuk/git-azure" target="_blank" rel="noopener noreferrer" class="">git-azure</a>. To bootstrap the project, I pretty much followed the <a href="http://www.windowsazure.com/en-us/develop/nodejs/tutorials/app-using-socketio/" target="_blank" rel="noopener noreferrer" class="">'Build a Node.js Chat Application with Socket.IO on a Windows Azure Cloud Service' tutorial</a>. This will get all of your scaffolding set up.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="my-nodejs-editor---webmatrix-2">My node.js editor - WebMatrix 2<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#my-nodejs-editor---webmatrix-2" class="hash-link" aria-label="Direct link to My node.js editor - WebMatrix 2" title="Direct link to My node.js editor - WebMatrix 2" translate="no">​</a></h3>
<p>After using the PowerShell cmdlets to scaffold my site, I used <a href="http://www.microsoft.com/web/webmatrix/" target="_blank" rel="noopener noreferrer" class="">Microsoft WebMatrix</a> to do the majority of the work. I am very biased towards WebMatrix, as I helped <a href="http://jbeckwith.com/2012/06/07/node-js-meet-webmatrix-2/" target="_blank" rel="noopener noreferrer" class="">build the node.js experience</a> in it last year. In a nutshell, it's rad because it has a lot of good editors, and just works. Oh, and it has IntelliSense for everything:</p>
<p><img decoding="async" loading="lazy" alt="I ❤️ WebMatrix" src="https://jbeckwith.com/assets/images/webmatrix-3ea89523742f2ff9efd732a208cf2ad5.png" title="WebMatrix FTW" width="1509" height="778" class="img_ev3q"></p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-the-windows-azure-npm-module">Install the Windows Azure NPM module<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#install-the-windows-azure-npm-module" class="hash-link" aria-label="Direct link to Install the Windows Azure NPM module" title="Direct link to Install the Windows Azure NPM module" translate="no">​</a></h4>
<p>The <a href="https://npmjs.org/package/azure" target="_blank" rel="noopener noreferrer" class="">azure npm module</a> provides the basis for all of the Windows Azure stuff we're going to do with node.js. It includes all of the support for using blobs, tables, service bus, and service management. It's even <a href="https://github.com/WindowsAzure/azure-sdk-for-node/" target="_blank" rel="noopener noreferrer" class="">open source</a>. To get it, you just need to cd into the directory you're using and run this command:</p>
<p><code>npm install azure</code></p>
<p>After you have the azure module, you're ready to rock.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-backend">The Backend<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#the-backend" class="hash-link" aria-label="Direct link to The Backend" title="Direct link to The Backend" translate="no">​</a></h3>
<p>The <a href="https://github.com/JustinBeckwith/wazstagram/tree/master/backend" target="_blank" rel="noopener noreferrer" class="">backend</a> part of this project is a worker role that accepts HTTP Post messages from the Instagram API. The idea is that their API batches messages, and sends them to an endpoint you define. Here's <a href="http://instagram.com/developer/realtime/" target="_blank" rel="noopener noreferrer" class="">some details</a> on how their API works. I chose to use <a href="http://expressjs.com/" target="_blank" rel="noopener noreferrer" class="">express</a> to build out the backend routes, because it's convenient. There are a few pieces to the backend that are interesting:</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-nconf-to-store-secrets-look-at-the-gitignore">Use <a href="https://github.com/flatiron/nconf" target="_blank" rel="noopener noreferrer" class="">nconf</a> to store secrets. Look at the .gitignore<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#use-nconf-to-store-secrets-look-at-the-gitignore" class="hash-link" aria-label="Direct link to use-nconf-to-store-secrets-look-at-the-gitignore" title="Direct link to use-nconf-to-store-secrets-look-at-the-gitignore" translate="no">​</a></h4>
<p>If you're going to build a site like this, you are going to need to store a few secrets. The backend includes things like the Instagram API key, my Windows Azure Storage account key, and my Service Bus keys. I create a keys.json file to store this, though you could add it to the environment. I include an example of this file with the project. <strong>DO NOT CHECK THIS FILE INTO GITHUB!</strong> Seriously, <a href="https://github.com/blog/1390-secrets-in-the-code" target="_blank" rel="noopener noreferrer" class="">don't do that</a>. Also, pay <strong>close attention</strong> to my <a href="https://github.com/JustinBeckwith/wazstagram/blob/master/.gitignore" target="_blank" rel="noopener noreferrer" class="">.gitignore file</a>. You don't want to check in any <em>.cspkg or</em>.csx files, as they contain archived versions of your site that are generated while running the emulator and deploying. Those archives contain your keys.json file. That having been said - nconf does makes it really easy to read stuff from your config:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// read in keys and secrets</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">nconf</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">argv</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">env</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">file</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'keys.json'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> sbNamespace </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nconf</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'AZURE_SERVICEBUS_NAMESPACE'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> sbKey </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nconf</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'AZURE_SERVICEBUS_ACCESS_KEY'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> stName </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nconf</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'AZURE_STORAGE_NAME'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> stKey </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> nconf</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'AZURE_STORAGE_KEY'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-winston-and-winston-skywriter-for-logging">Use <a href="https://github.com/flatiron/winston" target="_blank" rel="noopener noreferrer" class="">winston</a> and <a href="https://github.com/pofallon/winston-skywriter" target="_blank" rel="noopener noreferrer" class="">winston-skywriter</a> for logging<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#use-winston-and-winston-skywriter-for-logging" class="hash-link" aria-label="Direct link to use-winston-and-winston-skywriter-for-logging" title="Direct link to use-winston-and-winston-skywriter-for-logging" translate="no">​</a></h5>
<p>The cloud presents some challenges at times. Like <em>how do I get console output</em> when something goes wrong. Every node.js project I start these days, I just use winston from the get go. It's awesome because it lets you pick where your console output and logging gets stored. I like to just pipe the output to console at dev time, and write to <a href="http://www.windowsazure.com/en-us/develop/nodejs/how-to-guides/table-services/" target="_blank" rel="noopener noreferrer" class="">Table Storage</a> in production. Here's how you set it up:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// set up a single instance of a winston logger, writing to azure table storage</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> logger </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">winston</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Logger</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token literal-property property" style="color:#36acaa">transports</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">winston</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">transports</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Console</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">winston</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">transports</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Skywriter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">account</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> stName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> stKey</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token literal-property property" style="color:#36acaa">partition</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'os'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">hostname</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">':'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> process</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pid</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Started wazstagram backend'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-service-bus---its-pubsub--a-basket-of-kittens">Use <a href="http://msdn.microsoft.com/en-us/library/ee732537.aspx" target="_blank" rel="noopener noreferrer" class="">Service Bus</a> - it's pub/sub (+) a basket of kittens<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#use-service-bus---its-pubsub--a-basket-of-kittens" class="hash-link" aria-label="Direct link to use-service-bus---its-pubsub--a-basket-of-kittens" title="Direct link to use-service-bus---its-pubsub--a-basket-of-kittens" translate="no">​</a></h5>
<p><a href="http://msdn.microsoft.com/en-us/library/ee732537.aspx" target="_blank" rel="noopener noreferrer" class="">Service Bus</a> is Windows Azure's swiss army knife of messaging. I usually use it in the places where I would otherwise use the PubSub features of Redis. It does all kinds of neat things like <a href="http://www.windowsazure.com/en-us/develop/net/how-to-guides/service-bus-topics/" target="_blank" rel="noopener noreferrer" class="">PubSub</a>, <a href="http://msdn.microsoft.com/en-us/library/windowsazure/hh767287.aspx" target="_blank" rel="noopener noreferrer" class="">Durable Queues</a>, and more recently <a href="https://channel9.msdn.com/Blogs/Subscribe/Service-Bus-Notification-Hubs-Code-Walkthrough-Windows-8-Edition" target="_blank" rel="noopener noreferrer" class="">Notification Hubs</a>. I use the topic subscription model to create a single channel for messages. Each worker node publishes messages to a single topic. Each web node creates a subscription to that topic, and polls for messages. There's great <a href="http://www.windowsazure.com/en-us/develop/nodejs/how-to-guides/service-bus-topics/" target="_blank" rel="noopener noreferrer" class="">support for Service Bus</a> in the <a href="https://github.com/WindowsAzure/azure-sdk-for-node" target="_blank" rel="noopener noreferrer" class="">Windows Azure Node.js SDK</a>.</p>
<p>To get the basic implementation set up, just follow the <a href="http://www.windowsazure.com/en-us/develop/nodejs/how-to-guides/service-bus-topics/" target="_blank" rel="noopener noreferrer" class="">Service Bus Node.js guide</a>. The interesting part of my use of Service Bus is the subscription clean up. Each new front end node that connects to the topic creates it's own subscription. As we scale out and add a new front end node, it creates another subscription. This is a durable object in Service bus that hangs around after the connection from one end goes away (this is a feature). To make sure sure you don't leave random subscriptions lying around, you need to do a little cleanup:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">cleanUpSubscriptions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'cleaning up subscriptions...'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    serviceBusService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">listSubscriptions</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">topicName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">error</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> subs</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> response</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">!</span><span class="token plain">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'found '</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> subs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">' subscriptions'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">lt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> subs</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// if there are more than 100 messages on the subscription, assume the edge node is down</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">subs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">MessageCount</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">gt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'deleting subscription '</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> subs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">SubscriptionName</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    serviceBusService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">deleteSubscription</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">topicName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> subs</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access maybe-class-name">SubscriptionName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">error</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> response</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                            logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'error deleting subscription'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'error getting topic subscriptions'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cleanUpSubscriptions</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">60000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-newimage-endpoint">The <a href="https://github.com/JustinBeckwith/wazstagram/blob/master/backend/routes/home.js" target="_blank" rel="noopener noreferrer" class="">NewImage endpoint</a><a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#the-newimage-endpoint" class="hash-link" aria-label="Direct link to the-newimage-endpoint" title="Direct link to the-newimage-endpoint" translate="no">​</a></h5>
<p>All of the stuff above is great, but it doesn't cover what happens when the Instagram API actually hits our endpoint. The route that accepts this request gets metadata for each image, and pushes it through the Service Bus topic:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">serviceBusService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">sendTopicMessage</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'wazages'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> message</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'error sending message to topic!'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'message sent!'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-frontend">The Frontend<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#the-frontend" class="hash-link" aria-label="Direct link to The Frontend" title="Direct link to The Frontend" translate="no">​</a></h3>
<p>The <a href="https://github.com/JustinBeckwith/wazstagram/tree/master/frontend" target="_blank" rel="noopener noreferrer" class="">frontend</a> part of this project is (despite my 'web node' reference) a worker role that accepts accepts the incoming traffic from end users on the site. I chose to use worker roles because I wanted to take advantage of Web Sockets. At the moment, Cloud Services Web Roles do not provide that functionality. I could stand up a VM with Windows Server 8 and IIS 8, but see my aformentioned anxiety about managing my own VMs. The worker roles use <a href="http://socket.io/" target="_blank" rel="noopener noreferrer" class="">socket.io</a> and <a href="http://expressjs.com/" target="_blank" rel="noopener noreferrer" class="">express</a> to provide the web site experience. The front end uses the same NPM modules as the backend: <a href="https://github.com/visionmedia/express/" target="_blank" rel="noopener noreferrer" class="">express</a>, <a href="https://github.com/flatiron/winston" target="_blank" rel="noopener noreferrer" class="">winston</a>, <a href="https://github.com/pofallon/winston-skywriter" target="_blank" rel="noopener noreferrer" class="">winston-skywriter</a>, <a href="https://github.com/flatiron/nconf" target="_blank" rel="noopener noreferrer" class="">nconf</a>, and <a href="https://github.com/WindowsAzure/azure-sdk-for-node" target="_blank" rel="noopener noreferrer" class="">azure</a>. In addition to that, it uses <a href="http://socket.io/" target="_blank" rel="noopener noreferrer" class="">socket.io</a> and <a href="https://github.com/visionmedia/ejs" target="_blank" rel="noopener noreferrer" class="">ejs</a> to handle the client stuff. There are a few pieces to the frontend that are interesting:</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="setting-up-socketio">Setting up socket.io<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#setting-up-socketio" class="hash-link" aria-label="Direct link to Setting up socket.io" title="Direct link to Setting up socket.io" translate="no">​</a></h4>
<p>Socket.io provides the web socket (or xhr) interface that we're going to use to stream images to the client. When a user initially visits the page, they are going to send a <code>setCity</code> call, that lets us know the city to which they want to subscribe (by default all <a href="https://github.com/JustinBeckwith/wazstagram/blob/master/backend/cities.json" target="_blank" rel="noopener noreferrer" class="">cities in the system</a> are returned). From there, the user will be sent an initial blast of images that are cached on the server. Otherwise, you wouldn't see images right away:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// set up socket.io to establish a new connection with each client</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> io </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">require</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'socket.io'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">listen</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">server</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">io</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">sockets</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'connection'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">socket</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    socket</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'setCity'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'new connection: '</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">picCache</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">for</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">lt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> picCache</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> i</span><span class="token operator" style="color:#393A34">++</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                socket</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">emit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'newPic'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> picCache</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        socket</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="creating-a-service-bus-subscription">Creating a Service Bus Subscription<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#creating-a-service-bus-subscription" class="hash-link" aria-label="Direct link to Creating a Service Bus Subscription" title="Direct link to Creating a Service Bus Subscription" translate="no">​</a></h4>
<p>To receive messages from the worker nodes, we need to create a single subscription for each front end node process. This is going to create subscription, and start listening for messages:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// create the initial subscription to get events from service bus</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">serviceBusService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">createSubscription</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">topicName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> subscriptionId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'error creating subscription'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword control-flow" style="color:#00009f">throw</span><span class="token plain"> error</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">getFromTheBus</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="moving-data-between-service-bus-and-socketio">Moving data between Service Bus and Socket.IO<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#moving-data-between-service-bus-and-socketio" class="hash-link" aria-label="Direct link to Moving data between Service Bus and Socket.IO" title="Direct link to Moving data between Service Bus and Socket.IO" translate="no">​</a></h4>
<p>As data comes in through the service bus subscription, you need to pipe it up to the appropriate connected clients. Pay special attention to <code>io.sockets.in(body.city)</code> - when the user joined the page, they selected a city. This call grabs all users subscribed to that city. The other <strong>important thing to notice</strong> here is the way <code>getFromTheBus</code> calls itself in a loop. There's currently no way to say "just raise an event when there's data" with the Service Bus Node.js implementation, so you need to use this model.</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getFromTheBus</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword control-flow" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    serviceBusService</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">receiveSubscriptionMessage</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">topicName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> subscriptionId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">timeoutIntervalInS</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">error</span><span class="token parameter punctuation" style="color:#393A34">,</span><span class="token parameter"> message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword control-flow" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">error </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token maybe-class-name">No</span><span class="token plain"> messages to receive</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'no messages...'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'error receiving subscription message'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> body </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token known-class-name class-name">JSON</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">parse</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">body</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'new pic published from: '</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token function" style="color:#d73a49">cachePic</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pic</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            io</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">sockets</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">city</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">emit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'newPic'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pic</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            io</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">sockets</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">universe</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">emit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'newPic'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> body</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">pic</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">getFromTheBus</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// if something goes wrong, wait a little and reconnect</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    logger</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">error</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'error getting data from service bus'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> e</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">setTimeout</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">getFromTheBus</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="learning">Learning<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#learning" class="hash-link" aria-label="Direct link to Learning" title="Direct link to Learning" translate="no">​</a></h3>
<p>The whole point of writing this code for me was to explore building performant apps that used a rate limited API for data. Hopefully this model can effectively be used to accept data from any API responsibly, and scale it out to a number of connected clients to a single service. If you have any ideas on how to make this app better, please let me know, or submit a PR!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="questions">Questions?<a href="https://jbeckwith.com/blog/2013/01/30/building-scalable-realtime-services-with-node-js-socket-io-and-windows-azure#questions" class="hash-link" aria-label="Direct link to Questions?" title="Direct link to Questions?" translate="no">​</a></h3>
<p>If you have any questions, feel free to submit an issue here, or find me <a href="https://twitter.com/JustinBeckwith" target="_blank" rel="noopener noreferrer" class="">@JustinBeckwith</a></p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="azure" term="azure"/>
        <category label="featured" term="featured"/>
        <category label="microsoft" term="microsoft"/>
        <category label="node" term="node"/>
        <category label="service-bus" term="service-bus"/>
        <category label="socketio" term="socketio"/>
        <category label="webmatrix" term="webmatrix"/>
        <category label="azure" term="azure"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[5 steps to a better Windows command line]]></title>
        <id>https://jbeckwith.com/blog/2012/11/28/5-steps-to-a-better-windows-command-line</id>
        <link href="https://jbeckwith.com/blog/2012/11/28/5-steps-to-a-better-windows-command-line"/>
        <updated>2012-11-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[I spend a lot of time at the command line. As someone who likes to code on OSX and Windows, I've always been annoyed by the Windows command line experience. Do I use cmd, or PowerShell? Where are my tabs? What about package management? What about little frivolous things like being able to resize the window. I've finally got my Windows command line experience running smoothly, and wanted to share my setup. Here are my 5 steps to a Windows command line that doesn't suck.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Better command line" src="https://jbeckwith.com/assets/images/header-0a5ca72f359082dd9e2e50187bcafa8d.png" width="677" height="324" class="img_ev3q"></p>
<p>I spend a lot of time at the command line. As someone who likes to code on OSX and Windows, I've always been annoyed by the Windows command line experience. Do I use cmd, or PowerShell? Where are my tabs? What about package management? What about little frivolous things like <em>being able to resize the window</em>. I've finally got my Windows command line experience running smoothly, and wanted to share my setup. Here are my 5 steps to a Windows command line that doesn't suck.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-use-console2-or-conemu">1. Use Console2 or ConEmu<a href="https://jbeckwith.com/blog/2012/11/28/5-steps-to-a-better-windows-command-line#1-use-console2-or-conemu" class="hash-link" aria-label="Direct link to 1. Use Console2 or ConEmu" title="Direct link to 1. Use Console2 or ConEmu" translate="no">​</a></h2>
<p>The first place to start is the actual console application. Scott Hanselman wrote an <a href="http://www.hanselman.com/blog/Console2ABetterWindowsCommandPrompt.aspx" target="_blank" rel="noopener noreferrer" class="">excellent blog post</a> on setting up <a href="http://sourceforge.net/projects/console/" target="_blank" rel="noopener noreferrer" class="">Console2</a>, and I've been using it ever since. It adds tabs, a resizable window, transparency, and the ability to run multiple shells. I choose to run PowerShell (you should too, keep listening). There are <a href="http://www.hanselman.com/blog/ConEmuTheWindowsTerminalConsolePromptWeveBeenWaitingFor.aspx" target="_blank" rel="noopener noreferrer" class="">other options</a> out there, but I've really grown to love Console2.</p>
<p><img decoding="async" loading="lazy" alt="Console2" src="https://jbeckwith.com/assets/images/console2-f6404da0172feed42d665f061188107d.png" width="677" height="468" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-use-powershell">2. Use PowerShell<a href="https://jbeckwith.com/blog/2012/11/28/5-steps-to-a-better-windows-command-line#2-use-powershell" class="hash-link" aria-label="Direct link to 2. Use PowerShell" title="Direct link to 2. Use PowerShell" translate="no">​</a></h3>
<p>I won't spend a ton of time evangelizing PowerShell. There are a few good reasons to dump cmd.exe and move over:</p>
<ul>
<li class=""><strong>Most of the things you do in cmd will just work.</strong> There are obviously some exceptions, but for the better part all of the things I want to do in cmd are easily done in PowerShell.</li>
<li class=""><strong><a href="http://blogs.msdn.com/b/powershell/archive/2008/01/31/tab-completion.aspx" target="_blank" rel="noopener noreferrer" class="">Tab Completion</a> and <a href="http://technet.microsoft.com/en-us/library/ee176848.aspx" target="_blank" rel="noopener noreferrer" class="">Get-Help</a> is awesome.</strong> PowerShell does a great job of making things discoverable as you learn.</li>
<li class=""><strong>It's a sane scripting tool.</strong> If you've ever tried to do anything significant in a batch script, I'm sorry. You can even create your <a href="http://community.bartdesmet.net/blogs/bart/archive/2008/02/03/easy-windows-powershell-cmdlet-development-and-debugging.aspx" target="_blank" rel="noopener noreferrer" class="">own modules and cmdlets</a> using managed code, if that's your thing.</li>
<li class=""><strong>Microsoft is releasing a lot of stuff built on PowerShell.</strong> Most of the new stuff we release is going to have great PowerShell support, including <a href="http://msdn.microsoft.com/en-us/library/windowsazure/jj156055.aspx" target="_blank" rel="noopener noreferrer" class="">Windows Azure</a>.</li>
<li class=""><strong>It's a growing community.</strong> Sites like <a href="http://powershell.org/" target="_blank" rel="noopener noreferrer" class="">PowerShell.org</a> and <a href="http://psget.net/" target="_blank" rel="noopener noreferrer" class="">PsGet</a> provide a great place to ask questions and look at work others have done.</li>
</ul>
<p>Now that I've sold you, there are a few things you'll find through here that make using PowerShell a bit easier. To use this stuff, you're going to want to set an execution policy in PowerShell that lets you run custom scripts. By default, the execution of PS scripts is disabled, but it's kind of necessary to do anything interesting. I lead a wild and dangerous life, so I use an unrestricted policy. To set your policy, first run Console2 (or PowerShell) as an administrator:</p>
<p><img decoding="async" loading="lazy" alt="Run as administrator" src="https://jbeckwith.com/assets/images/console2-as-administrator-fa2de8234155a891c80413fce8c414db.png" width="417" height="235" class="img_ev3q"></p>
<p>Next, use the Set-ExecutionPolicy command. Note, this means any un-signed script can be run on your system, if you run it, and many people choose to use RemoteSigned. Here is the <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-7.4" target="_blank" rel="noopener noreferrer" class="">official doc on Set-ExecutionPolicy</a>.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Set-ExecutionPolicy Unrestricted</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="Set execution policy" src="https://jbeckwith.com/assets/images/set-executionpolicy-65dcb6c361abdae015b1e35a0e4bcdef.png" width="677" height="155" class="img_ev3q"></p>
<p>Now you're ready to start doing something interesting.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-use-the-chocolatey-package-manager">3. Use the Chocolatey package manager<a href="https://jbeckwith.com/blog/2012/11/28/5-steps-to-a-better-windows-command-line#3-use-the-chocolatey-package-manager" class="hash-link" aria-label="Direct link to 3. Use the Chocolatey package manager" title="Direct link to 3. Use the Chocolatey package manager" translate="no">​</a></h3>
<p>Spending a lot of time in Ubuntu and OSX, I got really used to <code>sudo apt-get install &lt;package&gt;</code> and <a href="http://mxcl.github.com/homebrew/" target="_blank" rel="noopener noreferrer" class="">`brew install `</a>. The closest I've found to that experience on Windows is the <a href="http://chocolatey.org/" target="_blank" rel="noopener noreferrer" class="">Chocolatey package manager</a>. Chocolatey has all of the packages you would expect to find on a developer's machine:</p>
<p><img decoding="async" loading="lazy" alt="list packages" src="https://jbeckwith.com/assets/images/choc-list-f6559ffd2425592e90131d7992f93020.png" width="677" height="299" class="img_ev3q"></p>
<p>To install Chocolatey, just run cmd.exe and run the following command (minus the c:&gt; part):</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">C:\&gt; @powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('http://bit.ly/psChocInstall'))" &amp;&amp; SET PATH=%PATH%;%systemdrive%\chocolatey\bin</span><br></div></code></pre></div></div>
<p>And you're ready to rock. If you want to install something like 7zip, you can use the cinst command:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cinst 7zip</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="install 7zip" src="https://jbeckwith.com/assets/images/7zip-install-4da131a571e62435aa0a6f0079811b41.png" width="677" height="299" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-use-an-alias-for-sublimetext">4. Use an alias for SublimeText<a href="https://jbeckwith.com/blog/2012/11/28/5-steps-to-a-better-windows-command-line#4-use-an-alias-for-sublimetext" class="hash-link" aria-label="Direct link to 4. Use an alias for SublimeText" title="Direct link to 4. Use an alias for SublimeText" translate="no">​</a></h3>
<p>This seems kind of trivial, but one of the things I've really missed on Windows is the default shortcut to launch <a href="http://www.sublimetext.com/" target="_blank" rel="noopener noreferrer" class="">SublimeText</a>, <a href="http://www.sublimetext.com/docs/2/osx_command_line.html" target="_blank" rel="noopener noreferrer" class="">subl</a>. I use my PowerShell profile to create an alias to SublimeText.exe, which allows me to <code>subl file.txt</code> or <code>subl .</code> just like I would from OSX. <a href="http://www.howtogeek.com/50236/customizing-your-powershell-profile/" target="_blank" rel="noopener noreferrer" class="">This article</a> gives a basic overview on how to customize your PowerShell Profile; it's really easy to follow, so I won't go into re-creating the steps.</p>
<p><img decoding="async" loading="lazy" alt="edit profile" src="https://jbeckwith.com/assets/images/create-profile-8a3ae2182d588431de11bc1235bb350d.png" width="677" height="299" class="img_ev3q"></p>
<p>After you've got your PowerShell profile created, edit the script, and add this line:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Set-Alias subl 'C:\Program Files\Sublime Text 2\sublime_text.exe'</span><br></div></code></pre></div></div>
<p>Save your profile, and spin up a new PowerShell tab in Console2 to reload the session. Go to a directory that contains some code, and try to open it:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">subl .</span><br></div></code></pre></div></div>
<p>This will load the current directory as a project in SublimeText from the command line. Small thing, but a nice thing.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-use-psget-and-posh-git">5. Use PsGet and Posh-Git<a href="https://jbeckwith.com/blog/2012/11/28/5-steps-to-a-better-windows-command-line#5-use-psget-and-posh-git" class="hash-link" aria-label="Direct link to 5. Use PsGet and Posh-Git" title="Direct link to 5. Use PsGet and Posh-Git" translate="no">​</a></h3>
<p>One of the nice things about using PowerShell over cmd is the community that's starting to emerge. There are a ton of really useful tools and cmdlets that others have already written, and the easiest way to get at most of these is to use <a href="http://psget.net/" target="_blank" rel="noopener noreferrer" class="">PsGet</a>. PsGet provides a super easy way to install PowerShell modules that extend the basic functionality of the shell, and provide other useful libraries. To install PsGet, run the following command from a PowerShell console:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">(new-object Net.WebClient).DownloadString(&amp;quot;http://psget.net/GetPsGet.ps1&amp;quot;) | iex</span><br></div></code></pre></div></div>
<p>If you get an error complaining about executing scripts, you need to go back to #2. Immediately, we can start using the <code>Install-Module</code> command to start adding functionality to our console.</p>
<p><img decoding="async" loading="lazy" alt="Install PsGet" src="https://jbeckwith.com/assets/images/psget-f1aecddd92d1045543aa360e2992c9cb.png" width="677" height="267" class="img_ev3q"></p>
<p>The first module that led me to PsGet is a package that adds status and tab completion to git. Phil Haack did a <a href="http://haacked.com/archive/2011/12/13/better-git-with-powershell.aspx" target="_blank" rel="noopener noreferrer" class="">great write up</a> on setting up <a href="https://github.com/dahlbyk/posh-git/" target="_blank" rel="noopener noreferrer" class="">posh-git</a>, and I've since discovered a few other <a href="http://pscx.codeplex.com/" target="_blank" rel="noopener noreferrer" class="">cool things</a> in the PsGet gallery. Installing Posh-Git is pretty straight forward:</p>
<p><img decoding="async" loading="lazy" alt="Install Posh-Git" src="https://jbeckwith.com/assets/images/install-posh-git-9a0bf2d363fcfb4677fa345a84cbefa6.png" width="677" height="187" class="img_ev3q"></p>
<p>The first nice thing here is that I now have command completion. As I type <code>git sta</code> and hit <code>&lt;tab&gt;</code>, it will be completed to <code>git status</code>. Some tools like <a href="https://github.com/MSOpenTech/posh-npm" target="_blank" rel="noopener noreferrer" class="">posh-npm</a> will even search the npm registry for packages using tab completion. The other cool thing you get with this module is the status of your repository right in the prompt:</p>
<p><img decoding="async" loading="lazy" alt="posh git" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAqUAAACLCAMAAABvPxBvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAMAUExURQICAwICDAIHDwILFBAQFhARFxkaJBocJxsdKxwfLwI1Ax0hMx0jNh8lPCQOFj4CAz4TFj4TGSUlJiIiLyYnNyAnPyYoNyYoOCcqPSgqPQICRgIoYyUlRSEpRSIrSCMtTCQuTiktQiktQyUlWyowSCwzTi0zTy41VS02VS86XDE8UjA5XDA5XTI8YjE8YzM/aTQ/aQJcAwJFRgJFfCVNRSVNWzZFVThHWzpMUztOWD9UVzxRXSVNazNAaTRAaTVCbjRCbztNZjVEdDVFdTdHeTdHejdIej1TZD9VaDxScT5UdiVpayVpdkUCA1cHA1cVGUolJm4LA24OCG4VD24YFm4YGWIoA2MlJmMmJkolRUUoY2IoRmMlW0pNJntFA2NNJmNOJnRNJnROJmNpJnRpJkpNRU1PXUFXXE5RX1dXWEpNa0VFfEFZYENcZURda1BUZFFUaVJYbVRadFRceVZffk5uXkZiY0Vgb0ppY0xtakdkd09wYlR7entFRmJFY2NNa2NpW3R9W2JifGN9a3t7fChilUJSg0p9gkp9g0V7lVhig1ljiFpmi1xokEV7rWZzmnt7lQKCAwKjAzWCAwLEAwLkA1+Mb1yIdGOMdmOUb2SWdGKUfGSYdXuFb3uUY2uifG6oem+qfHusfHOxfHi5f2OMkGKUlXSbkGKUrXuslXusrYMOCIMTDIMVD4MYFIMYGZkTDJkVD5kYFJkYFpkYGYI1A4JpJoJqJpRiKYJ9RZB9RZR7RrJJSqx7Rqx7fIKMW4Kba4iTe5SUY5Cba5SUfJSsfKCMW6CMXKCba6yUY6CtdqCtd6ysfKPkA8SCA+TkA5SUlYGKqoKtkJCtg5CtkJSslZSsrayUlaCtg6CtkKyslaysrbi4udfX2OTk5QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHcexKIAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAC/xJREFUeF7tm4l/FVcVxx/giprKs5Y2wQUBRVFojHWNighaNZS4lFCX2MQV973urUosuMRCiVaRuhAgUpdWY4KgdU/ColSKGIjyt/g75547b2YyCS88CKd9v+8nb5Z7z525d+b7zp15HyjtJsQ7pd1nCJlFfj8TQhNaSmYZ8686QhNaSmYZ8686QhNaSmYZ8686QhNaSmYZ8686QhNaSmYZ8686QpOMpaUMVkhIDdyWYAW1Wlr6zr9SfJ2aktoxRYEVFFl67lxlmSU0yVj67XVr165buw5/a1+z7um0lNROIue0uVQELZK0yNJvrVnz+S++fs2aV68BT6tLS4eXnIzL8e7Wv7a3heLIeHeuYBKHyqD1lO1Nw3gXAtvOjLXvtYLA0Y6tZ0YW7be9hz7VWQpFCyUtsvSbq1/X/6OfrH7lavl7al1aekgEObapDHWObZpsZBWWQvCx9vNrerQDMUdvPUVLA8WSFln6jVfc0n9L/8tXXbtq1aprn1KXlo613y4LJLkzo6JqjuosRUKd3DTHiIXQUmUGufRTKz/Sv/L656181feuX7nyyXVpKab5UzDtXbo8eWzT7WdGF32lXBZtxrvL5etuhqVItWU4Jj5qvh1uPTWKEugN1FIR/GhHEnW0A1FDradkkseRxtpvKy/5Y3mrxo+1f61d4hCg8Q9NS9F1xXZTVGfpTJ5LP/ncD/c/e8Vr96z43J4frnhCfb494ZEUCRMTv/iqlpalBIp1w7dD+iQJ5xAgWXAUj6AI182UpVpbiRqRqK628S64P7Tk5Fi7xAxJvhZLoeSQfOTwi/Y/7CxNsIIiS4OgRZqGJhlLP7H8Q/3Ln7X8ZS/6wY8/s/zx9Wkp0iDchFtiaLAUiQ766Fpyp71atUnl8AtuEg9HK1qJpWKoSIc3pDaxbihEqXxYj7VrGsV7Fta6g+lfbJZE+nCb8Sdj/lVHaJKx9OPL3tf/wu++ZM9zPvvMZcseV5+Wwj04BwnFSrVUlMFCkyTK8SdxmOaHWx/svmvT3lHJtSExAn3H3yp+yh6m+aHWB7vu6tg7suSkVmFWVyG1Nr7ji8KhkpZmCU0yln5s6Uv7v9C/9MVLhcfWp6WY3N+NiXm49XewcnpLR5f86ab9w23YEs/02TLkUlCxdESihtqwZVVBTAVvWYmlZiYtzRCaZCz96OLF3+//9GLlGY+pT0sxub8DguF1CMu0pbpOz/hw6z1Q77qbwwOpyppYmsz4MeqdkM9ErlgaZ3os7DGAlmYJTTKWvv/qa665WsHq0XVqaciKWEK+tKXHNkmKTb09wVTE6NsP3pwsxSaWVqK68ACgUUc7UDf2gfAT6Qiqx7vkVSpYOt4lEW8/SUszhCYZS9+78Korr7xKWbjwUXVq6bFN4sh4tyzTlkKlcvkN4qJsqEdBVagnP0SFVJpYmouCj5InEbdXnJQ0CsRas1RslgdaWpohNMlY+qRHpnhEnVpK/JG2lP9yj/gkYykhLqGlxD+0lPiHlhL/0FLiH1pK/ENLiX8SS/9MiD+CnBVL7bd8Qi4b5/6Xg5YSd9BScqmR/2En2O4FQEvJpcYkpaXEMSbpLFva+LONtlUdM42PXGi7PNUe52Kdj2QxSS+5pb0TE0d6OrWB0HNQVyg92IMa3ZkOiy+Vmk5PTEwcX297BfTGSCVpNzAxcf/dWJ3NaFRwtGz7SHKc3DhA44FU9y0OYwKZcxUfN0vjAWnSMu31uPPEid/aZi0sGLzHtrJsGCyuaBgcvNc2AwvC7j9O/FPXU1LNuM+LSXoRLN1s60JLe/8gt65ydxt/GtTYhrvSCHvOR4wXspIYu4rFje3Enl65+fuyya4F/WqZTnojHic/DiHdf4vD6Xo78+dSYj+L+9t0Gsff9rfp+nPn9FbstPWUzFMJG+4N6zwL7inNufGNtpNi3n2oy5Q3mLTan8YD53Nxivszqbw4ziSt3dLNm6OmBZY2HbZgjCc4YUknsRS57j9/CclNZBqQHCuRVl5JZtjsVFF6J6Qo1GtOFHmQxKS0Z2KL5ciY3GLzfRsRcvytp5G0enAmsVQq4/msveT4FulJ7I8doDIOnFeOL/VfQv9zcQCWShSO34saO27sZ9Lf2M7O33R4l36QT7XBwNmv5lKyWjG/b2dfX3NfX6mERd92KUbBzp2oEJolAvtavH27xFWIdhZbKjQUWPrEG0qluT+3HaXB2tu3JjdJNR6YQNcP5sddIXffbLxxP39/TdKaLYWkUdMCS1vkhEq01JJOtFRuruQ6ST89cttk2mtBd608nUwll8pHDprUJ9/BoEmPGCdbsR1GK2FiqXRAOyQ2iKWaUMP5kvZYSnHSn3CcZBwDUn9En0N1xs/FAbU0WC2DtOMm/bR1brxNh1sO9nai7vmoHsARBtDZpr9bG0WtmN/X3NxX2t5cgpClnVhsh6o7VEuJwWo+ymS7GbI2S1Sk2NJ5g/eV5v7yCtmc82YtyaKW/sJ2lJylEEyvr4G+N51OriRI7k9AStP3LY437ufur0laq6WiaNR0WksTQu+jpfjuSW4K36VEo6QcaLw6kLY0qU+uQjhurI/7gtowEGSVeKmvWBrDQrycCAZV+hPKY1S0T/ebYk6oxAG1FKcZOBKeCKw89jOs8+NtOizOo04rcAS9czKYhGAp1NshlmryFAllLdXB0pBTpaBZM21k7q8GBUmWGUvnvOWGhsHfwEQJSaXSOTdK+K+vqMJSdFOTn4JLEkecG7eRv29xvHE/d39N0totjYviGV96nSUkHbE0Vkpu0hsqJNZoOdB4Xcj9r1ho9clVsGuT1IfzJFsDW/TiSKU0UUulSXI+u6o9nVJV6U9oHbuatzQfB4Kl295297Yva3DuboV1frw4LrLKrvX6W4GMQXKtbiRkLe2TnGmpsjmdS8Mqbyk4z4zfEFzNI8+k2Rk/kliqScDQ6xSGVGypkLpvyXhjXO7+mqQ1W6p+Tmmpvuk1HsCp44xv3e+BCvKRuyFaJG+E1sVYDjQeM23Tv2VEWMuMktRjI7wFhauSGqUU6FVQtfZttJelXR+UalVRvIqXxNrDHxUk9YaqFXEcUgnFtKnMXPk4lKhaLVsOtjygW1Yc+2nr3HiD/bvWy11uOo12A5lvoJCxFGuZ/cMMjxLdwLNAaUeUc4aWLsBbUhFz35R/e4qYpdkJX6+PPBVNGrch9an7low3xqFV+v6apLW/PVUoslSeCzWjVywNSUd+2cFKqrUibEiiDzNeLI/xKJDDYIbQp/OkHo/fWId2x9fjob0TJXqBpJ2Wy/M9HvLlzUgaSLMw43Zau7jWA8p3B1Q6kJxfOhBnKHnqv18eTHNx6IDu4isVnl2xrwWhn5V1aGfnl1FtxEIHcPYOnGDfHSgP99kQKzCh72iW96JmvBr17YCmeHkKM768TsnaCmSpTwQJwc4FMpNPNjI8ERTZuCH/S9QGa62Whp/QUsj1eeBgwbiN3H2T66XjjftyJVL31yS95JYWYN+yqplpfKS4XZI8q6ba819oP4uQXJIlmWGdMHV/LuJ1MEkvh6WXEyRU+eZ6B6kkM5GCi/Sr/sViql/1C3peAyZpvVlKHlKYpLSUOMYkrcXS/2ahpcQftJT4h5YS/9BS4h9aSvxDS4l/aCnxDy0l/qGlxD+0lPiHlhL/0FLiH1pK/ENLiX9oKfEPLSX+oaXEP/y3+sQ/tJT4h5YS/9BS4h9aSvxDS4l/aCnxDy0l/qGlxD+0lPiHlhL/0FLiH1pK/ENLiX9oKfEPLSX+oaXEP7SU+IeWEv/QUuIfWkr8Q0uJf2gp8Q8tJf6hpcQ/tJT4h5YS/9BS4h9aSvxDS4l/aCnxDy0l/qGlxD+0lPiHlhL/0FLiH1pK/ENLiX9oKfEPLSX+oaXEP7SU+IeWEv/QUuIfWkr8Q0uJf2gp8Q8tJf6hpcQ/tJT4h5YS/9BS4h9aSvxDS4l/aCnxj1q6Wf0MS1pK3BEsFUF1QUuJQ8zSzfqhpcQl4bkUipqktJT4w96eEklpKfGHWWqvToCWEndESxNoKXEHLSX+oaXEP7SU+Of8lhLijyBnYikhbqGlxD+0lPiHlhL/0FLiH1pK/ANLCfHN7t3/B1T9PzozFR86AAAAAElFTkSuQmCC" width="677" height="139" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="wrapping-up">Wrapping up<a href="https://jbeckwith.com/blog/2012/11/28/5-steps-to-a-better-windows-command-line#wrapping-up" class="hash-link" aria-label="Direct link to Wrapping up" title="Direct link to Wrapping up" translate="no">​</a></h3>
<p>These are just the ways I know how to make the command line experience better. If any one else has some tips, I'd love to hear them!</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="console" term="console"/>
        <category label="featured" term="featured"/>
        <category label="node" term="node"/>
        <category label="posh-git" term="posh-git"/>
        <category label="powershell" term="powershell"/>
        <category label="tools" term="tools"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[WebMatrix and Node Package Manager]]></title>
        <id>https://jbeckwith.com/blog/2012/09/07/webmatrix-and-node-package-manager</id>
        <link href="https://jbeckwith.com/blog/2012/09/07/webmatrix-and-node-package-manager"/>
        <updated>2012-09-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A few months ago, we introduced the new node.js features we've added to WebMatrix 2. One of the missing pieces from that experience was a way to manage npm (Node Package Manager) from within the IDE. This week we shipped the final release of WebMatrix 2, and one of the fun things that comes with it is a new extension for managing npm.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="NPM and WebMatrix" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAl2cEFnAAAAgAAAAIAAMOExmgAAAVJJREFUeNrt2cEJhDAQQFEVSxLM9n9YQYvaJsK+g/8VMCR85pKs9ziXOJs+wNsVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYPusQcf30nf5q+czpsxpA7ACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAGzaf4Ay611e/We0AVgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArALbe49RneLU2ACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXAfjlHCXcnYwntAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDExLTA2LTA1VDA5OjQwOjU1KzAwOjAwp0C1owAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMS0wNi0wNVQwOTo0MDo1NSswMDowMNYdDR8AAAAXdEVYdHBuZzpiaXQtZGVwdGgtd3JpdHRlbgAIp8Qs8gAAADJ0RVh0UE5HOmNIUk0AY2h1bmsgd2FzIGZvdW5kIChzZWUgQ2hyb21hdGljaXR5LCBhYm92ZSkH0UjaAAAAKXRFWHRQTkc6Z0FNQQBnYW1tYT0wLjQ1NDU1IChTZWUgR2FtbWEsIGFib3ZlKRISLKcAAAAUdEVYdFBORzpJSERSLmJpdF9kZXB0aAA4KYV+UAAAABV0RVh0UE5HOklIRFIuY29sb3JfdHlwZQA2BkqnKwAAABt0RVh0UE5HOklIRFIuaW50ZXJsYWNlX21ldGhvZAAw+zsHjAAAABx0RVh0UE5HOklIRFIud2lkdGgsaGVpZ2h0ADE2LCAxNjjVBg0AAAAodEVYdFBORzpwSFlzAHhfcmVzPTI4MzUsIHlfcmVzPTI4MzUsIHVuaXRzPTGCKXI+AAAAKHRFWHRQTkc6c1JHQgBpbnRlbnQ9MCAoU2VlIFJlbmRlcmluZyBpbnRlbnQp8hEU9QAAAABJRU5ErkJggg==" width="128" height="128" class="img_ev3q"></p>
<p>A few months ago, we introduced the new <a href="http://jbeckwith.com/2012/06/07/node-js-meet-webmatrix-2/" target="_blank" rel="noopener noreferrer" class="">node.js features we've added to WebMatrix 2</a>. One of the missing pieces from that experience was a way to manage <a href="https://npmjs.org/" target="_blank" rel="noopener noreferrer" class="">NPM</a> (Node Package Manager) from within the IDE.</p>
<p>This week we shipped the final release of WebMatrix 2, and one of the fun things that comes with it is a new extension for managing NPM. For a more complete overview of the WebMatrix 2, check out <a href="http://vishaljoshi.blogspot.com/2012/06/announcing-webmatrix-2-rc.html" target="_blank" rel="noopener noreferrer" class="">Vishal Joshi's blog post</a>.</p>
<p>If you want to skip all of this and just download the bits, here you go:</p>
<p><a href="http://go.microsoft.com/?linkid=9809776" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="http://lh5.ggpht.com/-lm1GuUL20p8/T9HReoCZk7I/AAAAAAAABU4/uO7oVvNCGPQ/image%25255B4%25255D.png?imgmax=800" alt="image" title="image" class="img_ev3q"></a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="installing-the-extension">Installing the Extension<a href="https://jbeckwith.com/blog/2012/09/07/webmatrix-and-node-package-manager#installing-the-extension" class="hash-link" aria-label="Direct link to Installing the Extension" title="Direct link to Installing the Extension" translate="no">​</a></h2>
<p>The NPM extension can be installed using the extension gallery inside of WebMatrix. To get started, go ahead and create a new node site with express using the built in template:</p>
<p><img decoding="async" loading="lazy" alt="Create a new express site" src="https://jbeckwith.com/assets/images/template-3375013aecfccdbc2f13e5609512764c.png" width="720" height="519" class="img_ev3q"></p>
<p>After you create the site, click on the 'Extensions' button in the ribbon:</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix Extension Gallery" src="https://jbeckwith.com/assets/images/extension-gallery-icon-07bfabcfc258360199d52d5d5e2ef15d.png" width="1173" height="237" class="img_ev3q"></p>
<p>Search for 'NPM', and click through the wizard to finish installing the extension:</p>
<p><img decoding="async" loading="lazy" alt="Install the NPM Gallery Extension" src="data:image/png;base64,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X4mWP5HEqiJpk3+d2fxzSW970l+J+lDEg88jsXpI2swutBp1YPWRtJmddDd/9ojjQNJmRtKd/dkjjgNJQwxJQ4xG0sBQVhH6mjQwBUlDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDDElDTI+S/mpOgTYkDTE9Svr1nAJtSBpiepT0WzkF2vQo6Xs5BdqQNMT0KOn7OQXakDTE9Cjpr+UUaEPSENOjpN/OKdCmR0k/yCnQhqQhpkdJfyOnQJseJf3NnAJtSBpiepT0OzkF2vQo6W/nFGhD0hBD0hDTo6S/k1OgTY+S/m5OgTYkDTE9Svp7OQXa9Cjp7+cUaEPSENOjpN/NKdCmR0n/IKdAG5KGmB4lvZ9ToE2Pkv5hToE2JA0xPUr6vZwCbXqU9I9yCrQhaYjpUdLv5xRoQ9IQ06OkH+YUaNOjpD/IKdCGpCEmk/70qfDpsrSaSf8kp0Cb6i4dTddFr2TSP80p0KYeeLx46tSLOWtWMemf5RRoMxxLv9gomqTRWz368fDnOQXa9Cjp/8sp0IakIaZHSX+UU6BNj5L+OKdAG5KGmB4l/aucAoewikkDSyBpiCFpiCFpiCFpiCFpiCFpiCFpiCFpiCFpiCFpiCFpiCFpiCFpiCFpiCFptNroTp7xKE7ZRNJotbHXlWHSuWJ5JI3FkTTEkDTEkDTEkDTEkDTETOlvkNNHDG75xyRzJH1iMDgRp5gTSWNx8yU9rHCJpG8NrtnTNZLGkTrGpE9Y0Y6kcZSmJz14djB4NgYL1waDwVN7T/nTEknfqt4mdvwtO6MF7ueO+dwyjqSxuJakn9q7Nti7ZhlHhTlZImkbRgc/hZd8qz73NXvrTELSWFxL0lbu4NYtv1PHvN+rl0p6eJeO2aeuxbn9Ju23/0lIGoublfTe3rN2S7WpZ3himaQbY+lMOs5dlz4BSWNxs5Pee/ZZn1474WMFn4uVj5qZ9LXhbzxi4OHr/NxTRh2GpLG4WUn7cMPuqDY0ODE4sdxdOsYY5ffSPmfvkji3zzPwQGem9rew2UkvjKSxuMn9xe1zQbOStnOGXJwHSWNx3KUhhqQhhqQhJv93q13IM/I/pwUWQtIQQ9IQQ9IQQ9IQQ9IQQ9IQQ9IQQ9IQQ9IQQ9IQQ9IQQ9IQQ9IQE0kDQixpQMjBwf8DJJfqchLygZEAAAAASUVORK5CYII=" width="722" height="522" class="img_ev3q"></p>
<p>Now when you navigate to the files workspace, you should see the new NPM icon in the ribbon.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="managing-packages">Managing Packages<a href="https://jbeckwith.com/blog/2012/09/07/webmatrix-and-node-package-manager#managing-packages" class="hash-link" aria-label="Direct link to Managing Packages" title="Direct link to Managing Packages" translate="no">​</a></h3>
<p>While you're working with node.js sites, the icon should always show up. To get started, click on the new icon in the ribbon:</p>
<p><img decoding="async" loading="lazy" alt="NPM Icon in the ribbon" src="https://jbeckwith.com/assets/images/npm-icon-87a06808bf5ece44aa7de7bca72880c4.png" width="1173" height="218" class="img_ev3q"></p>
<p>This will load a window very similar to the other galleries in WebMatrix. From here you can search for packages, install, uninstall, update, any of the basic tasks you're likely to do day to day with npm.</p>
<p><img decoding="async" loading="lazy" alt="NPM Gallery" src="https://jbeckwith.com/assets/images/npm-dialog-b4214aa79dd30cdf95aefe9456709654.png" width="721" height="521" class="img_ev3q"></p>
<p>When you open up a new site, we also check your package.json to see if you're missing any dependencies:</p>
<p><img decoding="async" loading="lazy" alt="Missing NPM packages" src="data:image/png;base64,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" width="370" height="250" class="img_ev3q"></p>
<p>We're just getting started with the node tools inside of WebMatrix, so if you have anything else you would like to see added please hit us up over at <a href="https://webmatrix.uservoice.com/" target="_blank" rel="noopener noreferrer" class="">UserVoice</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="more-information">More Information<a href="https://jbeckwith.com/blog/2012/09/07/webmatrix-and-node-package-manager#more-information" class="hash-link" aria-label="Direct link to More Information" title="Direct link to More Information" translate="no">​</a></h3>
<p>If you would like some more information to help you get started, check out some of these links:</p>
<ul>
<li class=""><a href="http://bit.ly/LG7gs8" target="_blank" rel="noopener noreferrer" class="">WebMatrix on Microsoft.com</a></li>
<li class=""><a href="https://twitter.com/#!/webmatrix" target="_blank" rel="noopener noreferrer" class="">WebMatrix on Twitter</a></li>
<li class=""><a href="https://github.com/MicrosoftWebMatrix" target="_blank" rel="noopener noreferrer" class="">WebMatrix on GitHub</a></li>
<li class=""><a href="http://webmatrix.uservoice.com/" target="_blank" rel="noopener noreferrer" class="">WebMatrix on UserVoice</a></li>
<li class=""><a href="http://www.microsoft.com/Web/webmatrix/optimize.aspx" target="_blank" rel="noopener noreferrer" class="">WebMatrix and Open Source Applications</a></li>
<li class=""><a href="http://vishaljoshi.blogspot.com/2012/06/announcing-webmatrix-2-rc.html" target="_blank" rel="noopener noreferrer" class="">Vishal Joshi's blog post</a></li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="happy-coding">Happy Coding<a href="https://jbeckwith.com/blog/2012/09/07/webmatrix-and-node-package-manager#happy-coding" class="hash-link" aria-label="Direct link to Happy Coding" title="Direct link to Happy Coding" translate="no">​</a></h4>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="node" term="node"/>
        <category label="programming" term="programming"/>
        <category label="webmatrix" term="webmatrix"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[WordPress and WebMatrix]]></title>
        <id>https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix</id>
        <link href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix"/>
        <updated>2012-06-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[After releasing WebMatrix 2 RC this week, I'm excited to head out to NYC for WordCamp 2012. While I get ready to present tomorrow, I figured I would share some of the amazing work the WebMatrix team has done to create a great experience for WordPress developers.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="WordPress and WebMatrix" src="https://jbeckwith.com/assets/images/wp_title_header-e925a0e37c6b7a3720529a05bed1194d.png" width="430" height="290" class="img_ev3q"></p>
<p>After releasing WebMatrix 2 RC this week, I'm excited to head out to NYC for WordCamp 2012. While I get ready to present tomorrow, I figured I would share some of the amazing work the WebMatrix team has done to create a great experience for WordPress developers. For a more complete overview of the WebMatrix 2 RC, check out <a href="http://vishaljoshi.blogspot.com/2012/06/announcing-webmatrix-2-rc.html" target="_blank" rel="noopener noreferrer" class="">Vishal Joshi's blog post</a>.</p>
<p>If you want to skip all of this and just download the bits, here you go:</p>
<p><a href="http://bit.ly/L77V6w" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="http://lh5.ggpht.com/-lm1GuUL20p8/T9HReoCZk7I/AAAAAAAABU4/uO7oVvNCGPQ/image%25255B4%25255D.png?imgmax=800" alt="image" title="image" class="img_ev3q"></a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="welcome-to-webmatrix">Welcome to WebMatrix<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#welcome-to-webmatrix" class="hash-link" aria-label="Direct link to Welcome to WebMatrix" title="Direct link to Welcome to WebMatrix" translate="no">​</a></h2>
<p>WebMatrix gives you a couple of ways to get started with your application. Anything we do is going to be focused on building web applications, with as few steps as possible. WebMatrix supports opening remote sites, opening local sites, creating new sites with PHP, or creating an application by starting with the Application Gallery.</p>
<p><img decoding="async" loading="lazy" alt="Welcome to WebMatrix" src="https://jbeckwith.com/assets/images/wp_start_screen-56f29e920bf00167bd02bc4aada44335.png" width="800" height="550" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-application-gallery">The Application Gallery<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#the-application-gallery" class="hash-link" aria-label="Direct link to The Application Gallery" title="Direct link to The Application Gallery" translate="no">​</a></h3>
<p>We work with the community to maintain a list of open source applications that just work with WebMatrix on the Windows platform. This includes installing the application locally, and deploying to Windows Server or Windows Azure:</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix application gallery" src="https://jbeckwith.com/assets/images/wp_app_gallery-c7744d4b50b985d68726af9051476c9d.png" width="575" height="378" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="install-php-and-mysql-automatically">Install PHP and MySQL Automatically<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#install-php-and-mysql-automatically" class="hash-link" aria-label="Direct link to Install PHP and MySQL Automatically" title="Direct link to Install PHP and MySQL Automatically" translate="no">​</a></h3>
<p>When you pick the application you want to install, WebMatrix knows what dependencies need to be installed on your machine. This means you don't need to set up a web server, install and configure MySQL, mess around with the MySQL command line - none of that. It all just happens auto-magically.</p>
<p><img decoding="async" loading="lazy" alt="Install and setup automatically" src="https://jbeckwith.com/assets/images/wp_dependencies-ef58fc84550811c626afabe4ff7fff2d.png" width="724" height="401" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-dashboard">The Dashboard<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#the-dashboard" class="hash-link" aria-label="Direct link to The Dashboard" title="Direct link to The Dashboard" translate="no">​</a></h3>
<p>After installing WordPress and all of it's dependencies, WebMatrix provides you with a dashboard that's been customized for WordPress. We open up an extensibility model that makes it easier for open source communities to plug into WebMatrix, and we've been working with several groups to make sure we provide this kind of experience:</p>
<p><img decoding="async" loading="lazy" alt="WordPress Dashboard" src="https://jbeckwith.com/assets/images/wp_dashboard_clipped-4780529ddcb4f501ac5790ac7c38b3b4.png" width="727" height="405" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="protected-files">Protected Files<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#protected-files" class="hash-link" aria-label="Direct link to Protected Files" title="Direct link to Protected Files" translate="no">​</a></h3>
<p>When you move into the files work space, you'll notice a lock file next to many of the files in the root. We worked with the WordPress community to define a list of files that are protected in WordPress. These are files that power the core of WordPress, and probably shouldn't be changed:</p>
<p><img decoding="async" loading="lazy" alt="Locked system files" src="https://jbeckwith.com/assets/images/wp_locked_files-1a7dfea714070c6fa6099fdfc7605753.png" width="306" height="380" class="img_ev3q"></p>
<p>We won't stop you from editing the file, but hopefully this prevents people from making mistakes:</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix saves you from yourself" src="data:image/png;base64,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" width="372" height="252" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="html5--css3-tools">HTML5 &amp; CSS3 Tools<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#html5--css3-tools" class="hash-link" aria-label="Direct link to HTML5 &amp; CSS3 Tools" title="Direct link to HTML5 &amp; CSS3 Tools" translate="no">​</a></h3>
<p>The HTML editor in WebMatrix has code completion, validation, and formatting for HTML5. The editor is really, really good. The CSS editor includes code completion, validation, and formatting for CSS3, including the latest and greatest CSS3 modules. We also include support for CSS preprocessors like LESS and Sass.</p>
<p>I think my favorite part about the CSS editor is the way it makes dealing with color easier. If you start off a color property, WebMatrix will look at the current CSS file, and provide a palette built from the other colors used throughout your site. This prevents you from having 17 shades of the mostly same color blue:</p>
<p><img decoding="async" loading="lazy" alt="The CSS Color Palette" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgEAAACrCAMAAADIIL/yAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAMAUExURQAAAAEBASEhISIiIiMjIyQkJDMzMzQ0NDU1NTc3Nzg4OEFAQUJBQk1NTU5OTk9PT1VVVVZWVmJiYmNjY2RkZGVlZWZmZmdnZ2hoaGtra3R0dHV1dXZ2dnd3d010qk51q092rFB3rRmC0RqD0myMuG2NuW6Oum+Pu4EwJIIxJYMyJphXTZlYTppZT657c698dLB9dc5HH89IINBJIddoR9hpSNlqSd+HbuCIb+GJcIeHh4iIiImJiYyMjI2NjY6OjpiYmJmZmZqampubm5ycnKSkpKWlpaampqmpqaGptKKqtaOrtrOzs7S0tLW1tba2trG3vLK4vbO5vrm5ubq6uru7u7y8vL29vb6+vr+/v4mjxoqkx4ulyIymyaW51Ka61ae71qi817C3wLG4wbK5wr/EzMOclsSdl8WemNe9udi+utm/u+iEgumFg+qGhOelkeimkumnk+7Cte/DtvDEt8bGxsfHx8DFzcHGzsjIyMzMzM3Nzc7Ozs3S187T2M/U2dLS0tPT09nZ2dra2tvb29zc3N3d3d7e3sLP4cPQ4sTR48XS5N3f497g5N/h5d7l79/m8Ord2+ve3Ozf3fbf2Pfg2fjh2uLi4ubm5ufn5+Tn6eXo6ubp6+fq7Orq6ujq7Ojr7ens7urt7+3t7e7u7uDn8eHo8uvu8Ozu8Ozv8e3w8u7x8/Dy9PHz9fL09vj4+Pn5+f39/f7+/v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKNm+8AAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAHDBJREFUeF7tnYuD3EZ9x03sPkkTWkrb4ODbtI3jGBPn7uL4zDMJEJojCW0pTlofeMEtJk5bn32u3QQwpM2DHJgYEydtofRBD8rRl6V/sL/Hd6QZ7Yw0eqxWZ+8n8a30/f3mIc33RtqVbrXrj8r4wwkQUP54EkQMKOWAkACJgeLWCskCAQPUaYL+FbbdDzJzoLcAGypAagP6JYiw66/K+MsJEPjrAAjnoJgFAhlGvfjf4H8MWHdBDEAcFP+VAaEd2FIBUk4HjZQ6QAfHRnUMtweNW6BcDvRJLupeqwQdFyDd1GBTGSjEzy0gNaWJAzDaPiRug3IZkD1c3I4EG05AqOJnGRB2FNhWAoK9QQLUhtRzgMoYbR+aYIGCBqg+6jsA61VgPwGIOwdsbNgAlZtUnrUrDZNMgEAdUFKB5uWidnSS/2SwzKDn1o4oZjhIMAfqDsK/uTlQg1SkTd0BVi0QAlxETwv8uwHrhPYcK8REggOiBqjdUuxRp2jlee3YkAzIQZAWypu+A5iYki/8FD21+TcLSMRPCSwSCFtxB0QNULuEu2MBtTsKlWJDMiAHQVoorx8HxPDC5Lb9qwNExslE2I7bIGqA2iXYlTaIhIhIsXGTsSEGqEGQZidKF02dA3IA9QZ9Jf7FA0JFEA3FETRAjcTpUwDZjz4QnwDh6pr9YEMyIIdAlpWH5tGBWg6APh3YAWan/LMfRF0QIyAUxg3BDMhVcG9yIHpBig9kuCAmQKoDNiMHegAkERDc/rZ0wJ7XsOBjL16D/Oht+vH2j3SFHMC9/KHwgxAadkGIgPBD2V4sT1YGuRypwgEBxa4EcT/IsUHEADUebEYO9ABIIiAUOvDDBg7Ix73EAY/t3bv3MSwHePmul+UfeIF7p339pxAadkBEgCTbieXJyiCXIjUUQIhxakHYD3JsEDFAjUe3wgK6H+QwUAod+MG0HJAe330cS0FevOtP73oRy7YD0GMPEnZBRIAkW5btWsQMUEvRCgogRrj1IBwASRYIZECORlq3gBwASQyUdg74td27j+/Zs+fuO59N02fvZAe8RquafceePc9IAn7Qf1U8+RtPYomIcYBncxEQIMmWTdsBeUWI+0GOBQIZkGPRxi2gB0ASA6WVA47LsZ3G/dn3pen7nuUl+v+Zj7N6B/+UBM2K4OW7/iA/CEQdBTybi4AASbYRixOVQS2Di0+CIFGoCHEvSLFBJANyLNp4DuQQyGKgtHLAq7v50M5z/y+k6Z28xFPAnrtJfE1mgtc4QbOqeZsOAS/exaeDQnfnAbyRWCAQM0AtQ/ZMEcQIVBTYoy5IsUEkA3I0aB1ADII0BorbgR+UOmDCAnSCR/M7O+Djn/jEJ9QBSDULnKA/KvkR//6/nL8X0A4B9LoAgjaICJAKIChAKkX2TBHEGFQV2KU2iBdAEECMB40zUEpBKgHB6oCs1XRA+thj4oDX7riDfvJRQA4BtCBHAYIS8KMmrgMssAHNx7c8OoHsHAcEFNTGQKksUgApAqRaOE1XI10Nlyh1QNECn9u9e3ea3s3T/t089dPA82HgbjEFLTzzzJ49u+ldAGfVhh2ATtUB2ydAaoeOjAV0A9pSoFVQzPRXPCNqOcD6SOjuZ7DQGRfRo5rIQABI7cDwZEA2oCkD1DKQWfQAlmaOOsAeWxsMfAZkPgpgoTt2hgPQUg70MMgjIHSPr6PRiAPc0bWQgAVkeu9P037HGAfo5hBYrwB7l4HSErRugArQkg0iIZAlQOoYdJSAUA92gDu6DhrKgDoV4ABsjKJSBd3uXrScARmgLQeEvCDFALVT0E8BUi1yB8RMAlCngs8BDW3dBrSbAVnBQBZA0AMSMiCXM9FqGdLHHKh1IAdgdGMcME0LXFReKAK9L9CqAaryNyEQt0CgCKJl+BoOgVwLBMpAVxherXBAn5NAN0yxn1p1O1DVDEFHDOkQHNBltejnFHqKeluCymrSuOAk2g2LXRX7DLEMyF3Sab1SGYP1zkC1rUF1tWhc0IPUZWM5wNsGQhmQu6TTeqUyAUJHoNL2oL5aNC7oQeqy8TvgyipzJd1efeKJnyGqIKFDGlYcKCN1CRA6ApW2B/XVonHBSaQqh5I5YHU7Xb2S/OwJRAWEOqVRzcFCGiCw3g2oswNQYS0aF5xEqnIIO+DypfTKqTT9+hPfQZhBrFOaVCxlvKUQ6binqLQDUGEtGhecRKpyCDuApgAywaUv/cXXESYQ6praFaM7/mLBQAuktU5AhbVoWs6HdMIm6AAaffp36VJiOQChmYPuEBCmD9prDaqbHehHRmo7wO7eNk0BdEJ4OU2+lB0FEJo56I4AaeqguShKSmholqAjgISQAy7RFCBHgu/kZ4ISGADojgBp+nBTaLMMZAOIGZBnCrrCyLr1maDdQZkC+GU1fzcogSGA/giQ+gKtBkCSA0ICpBmDzpjeBBxggdhQ+k+gPwKkGYAO5EAvgigBYWDEOwCrAwAdEiDNBvRBgOQBCQM1wNwBHVDVieH01Ee0A7A2BNAjAdKcxjgOKLEAloeA9CcD4pym9OGAjodJ+pMBcU5TIh2AxWZ0PErS0wyIc5oS4QBKwEL6+OOfUmj5oEo51+7HgsXe3bF/SBwP+gogzmmK3wHm/oD0FP/IeRyvsQ54tcmfj1WCzgqQ5jSmZA7g+wO2T7VywPHqb5FoADo7H/5OCDuALw7SJBB2wPMHD34lTb9/8P77z/DwE+npQxQ4dFpymOk4AD3Gypx2OA6ApuiVgaID3vXrhDrgQRr979P/NPrXUnIBzwG0ZE8F0V8nMmdmBB2gU0DZHED/PvD8Vx6kl8NnztAvPw/94dPp6XwKmMJp4JyuIQdkFlBFwcXBgAP4lX/V4YAHMwdcOyS64dG5BQZPyAF6f0CFA87cL0cAHAw+wLPC4dOHJUOZ0nnAnA6xHKCCginAvCk0PG6gZT71u8YuOEijn37lIJ0ZknqGTwsz5g4YPgEHNOb5D2BBmDtg+HTtgIPPY0GYzidCc7qEHQALyHo15lzAx4P8CYHNo/O3A0Mnd4CsRvB4rew5Q0ccUIfkk+IAAsKcnU0LB8wt0BGz3Zl1HZDsAAcMuGteZrsz2zigRq/fWpaX60vyY0NWpka9rg2AmfbX74D8+wNW8emwoRcHbI1Goy0sF9eqqdu3W5ySOYDG/lSaXqZ/Fh04oJrRJg07ltN0f5qO6V80dft2ixN2AC4OXlmVF0OcA5bWl5bOpemx5eXlCzz8BA8/kaYrSzIHcMp6mm6wSK9P73paixKbPObkgpxN8gNPBZvpeDzav8Yxu4BLRd/muKgDfDsM0z+MYIg7E1w6RsP+Fi/xLz+5gF9o4HUOOLJB1Syu0OiTeD3dOEKaPaDjtXRt/9oYawwpKU8Ko63xKB2NxxSbO6Aj2AG6ywr7zD8FUHLmAAg+eM5/+EJ6QX75LzxMRliSgYYDzlPpxUTWjANsxmtr5AHLAWYKoPMB8gL9sN0xSXnf5riQA2Q4CSgKLg5eLhog7jNBOICmAfrln3DAQ5YD6JhAJnDZHNEI78+PAvR7r4cGXo5wwJw6WA5wRlXvD/AYoPS6gIEccGFZDgTH9OXIEo33dX4h4ICEHHDd/P47kzqd+vOvPRADyOkhrxgHPL3royLPaUnAAToF8JtB5/4AJsoBBJ0G0JngOTLDueUlPuTTqR+/HFkkzsMBMgewLRwHOO//dPrndwej0f7cAX+/691IuPkojkYRiVdMw9GEv0kqROQcEAatSXtsiXSF3gvU55du2jkg2zsBNN6VBULfIhOmewc0+YzwozfxQSDfPX4QJyC0YsYOoDMD+ThgjoW1e3wgrEBrwXQcUAbaIiDcalRtuuwbButFEFWgteAmdIB+yDVYKrddEwisF0EUQGzO3AE9g20v2XgkEBAKIAggNsd2AKQK5g4oUG9DsO0lZZBAQCiAIIDYnOk4wHsmeERP+dEYIasB9NNDD7iwVELPDqjakgKy5QRWPSCBgFAAQQCxDm4hvwPM/QGX6Kd7f0CHDpC1EEEHZPUEGbQDZMsZrHtAAgGhAIIAYh3cUiVzAK4MuPcHtHdA1qCuBdhZDqgxDpJOYNUDEggIBRAEEJtDuwtVFSvDxcHC1eFIB1xYXs7vD5CPfmXk1mkG3+BPhc8mR9dF5JsGKIUsI9eRz8mnA7iTwKDFWZSxFwdgbUVrcT5U3hEOwJoPZBAQCiBogNoYywFQDDIFrK4Wp4A4B2T3B8hn/ysiHtlY4etAS9eT8w8lKS+vbPDlouuUaRyAmwbMnQSCFpdMuYzIDjBrWstOcoAUwJIfqZDBehFEDVAbE3SA+d2fuEEgxgE8fDRQcgOQ3APAHFmSoaQ1vlDM45am6ywdu2AcQMk09OY6MhenGUGLS6YUYgeYNa3FpWcH1LdABVIfgdVJEM+A3BDeXb56zPcHZPcKZdRwgPyi5g7YkFkcdwREOADcog7Amg9kOCBUH9ldnhrM9wfIs4YcIh1As7lM07R4hIeLR47vEjZ3BOjYcQofL+j/hzMHsKh3Egha3Mz76gCzZhwww6OA9xeoHTG1aasOiNQksLvy7w9odB7Asz//ntMsziPJl39k5DZoVuc5gNYwdjTT8wnDOb2TQB1g7iQwaHE+JlCdvEJGwtrN6YBYtOUcyPWov7uqHVDamRZ3BETStwN0ILDcL9KyBeRadO8AdCbUncZ3BERzCzmgaAGotejaAeiKAKnA1O8I6N0BstFYbITsrUY1aMkMqLXo1AHoRwbkm52W2yrFFSg1QEED1Dp06AB0wgaRHUe9zkt2423V0gaI0aCYAWodunMA+uCC2A6jZudrprugsAFqNChmgFqHzhyALhRAcIdRs/M1011Q2AA1GhQzQK1Dcwc4XxKFDkyAcK88BZ4Gn8mB4uCGpOSTiixHUJnuxvJ2CJTNgR5ESmfFixWoVswpgh2l+B2QPV8gvVz8gxFrDtj9KhYw3D6Q0SfuBjahbt8rssuiUjS5oS8M9GhQDEAsJ8YBAn8seOWU+7WyRO6AvceLHZgEqX3SvwNKxxi1YaWIBofpALk4WHzEBOE4AA0HQWavtHdA+aDVRSsL1IZgDvRoUAxALCfWATwFXLpc+GppwnLAozerAzoFu6IXC0ArJ9IBPAVcoX8lDqCTwVfRcgDk9cvAHIBdwUBxQMgCgWhQjIFSQZwD5OLgKTkhLFwddOYAzwbkIK1vhuuASAsYkFAJ0qMLxDkguz+g8ZkgkvpnwA6o6wECOeWEE1966aVvMvQqsBblgPwWoUYOQMJsmHTAq8JrQLXfNvwWo5qP/3BQ7asWL76o2u8afo9R7f+Y/zXortntoHkf+tAHLTTvTwyfYzTvVxxU+wcH1Sxe0toIXeUfcXNAmGoHIDwrQg4wHlAN49/aAV+t6YDbMPaK5n1I8TtALKB5GHqgGoYeqJaRJN/U2ggROnYAfyKE6m0QbU7LGsIOUAuohvFXA5Q74Mc//rGOf4wDxADNHAALaB6Gn2joAK0md4Ds1U4dgE+FUX2OBNvQtg5rA2/XF4w/kTvgdywHvOc94TbFAJkFVMPYKxUOwPATsneS2xwLaB4MAAtoHoafqO+A27UKRhzwTv1BkW4cgOcMAa7cBnJzWleTb+Dt4oAkeeUVGGDSAWoAdkCgSTgAHlDtq1/7GoafUc0e/5YOuMF89rMwgFhA8zD0QDUMPRApeacMuaAOoHX+15EDCkg7OVAbg2raVJRt4O3iAKrrFSK3gAZzB5ABxAH+Jn0O+JoAA1gOwPATqvkdYFtA8zD+cIAYgByQeaCmA3i0MwvoUYAEUXaAA1ALAaEBZgPJAOQArosdAAuUOcDbZuYAsYBqAQdg9BnVajtALJA7ABao5wBqwww4gfMArN+KDpC6xAFqgYIDcBDo1wGWBTTvwxj/aTlAVvhHewfIOQCDdYIrz4FYZG/sA6dQDQGhAdkGkgO0LnWAsYAGfQ7wNToNB+QW0LwPf9h44INEJw7QxgrnAUkS7QBzfwB/LGw+HGTMyMvroZSfL8r15kh0gviHzqEaAkID8g3cQQ6ABT5IdOEAbYtwzwPiHSCsbk98IOg44H55yLRUnCHRCeIfPIlqCAgNsDYQe6JrB9B7gdwATRyQeUDzcgewBeo54B8JDD9BArWRG6BwHlDPAXxxsMQBp/mps/cfSg98+cCBLyfJAwcOHHguSc6weDq9dvDgQevRk3UePao9bWEAewNRmc8BYoA65wFsAOMAB9XIAZYHVCtxACygea4DzLtBY4BqB+QeIEGbMcABoN55gLk4aC4QMI+n72LECdcOpYfPpOmBB5LvHfgeV/+9A0ly4FrKjyHn54/zQ4nB8V4fO5lvoGw1AQeIBeo7QC0gBvA5oPYnQqDSATr8YoA6DnAtoA6QTKaOA8z3BzhfL24fBc4cTg/RINOwJ+9/LnmO5oDMAddkfsgc0PNzR8sd8OqEA9gCkqaBAjryBtUw9sLElSExgWrsgNwC0kbuAPGA5mXjT0x8JsgGKDjgVwXVHAN4HSBpoIYDsouD+VVCwnLAIRnl08YBNA3wHPCAjDxPAzaPzmYO0H1gAX2C0mBbpPIASHFAyAC1DigpZJeFAcfjHJDdH3DJvkHkU3hlJ9BpIE/2NOzPHZADwQP08n7tsfMI+r4fQY4NxC6w0UDfoHEvSHFAqEV3UT5UQ5QD8JtP5wHOHUKfAuyAw2foTIAcQNBpAJ0JfpnngAM0CdA5Av205oEZOAC7wEXCvYPGvSClQDgST0kFcXNANHwUyKDZgKxB7xFd+ncA+uOi4f5B816Q0itTd0DhEEAUPxHSZKx0Dm2gNlAE8RmADnhAQq885bRb3wHmXAA4DkjeT0eBiSmg8Bdm+f7AegR1knt3AKovrR8pkyDeJ086Dbd2gNRmAbkMZBIQKkAyAaGcp0K7G/FOQdUGqD6QUQTRPtlxDkCuAq0Mz59jKvi7yfxvSi0Q8eLLQJUekOABCQUQnESb5YaxEAQFYlEHmF05AwcgkYFSClINUEtBahFE24P6AiDJAxJcEOsRt+HZOiBm85FpgFoGMidAOILyVFQXBnkTIOyCWI+4Dc/AAW8u8hMnFUhlIDMDcglILIBgDBXpUl05yCyCqANCPeI27HdA9v0BV1Y//efQDNN0wNZodM9PsGxAZgZk66m0RZDoglgMVQU0XgFyXRBzQKhH3IZL5oDV7cmHCxBtHYA8BZphf5p+8T4sG5CZAbmWAxCIpKqMxqtAsgNCDgj1iNtw2AF8cdC5NAwiHLC+vnRkZWlDvkB2g79BlF71a2GX1tOj/MzZJFk8y08ZKDxulti8J01/cg8/ZnY8Hu1fG21qtUlyYmFh4fUkWUhopkjH8ijaLcq8555vU6nPvOMzWpxBgRzosVQV0nglyLZBxAGhHnEbDjuARn/71OXV1W9g3VBwQGGrRFpfSpfW1+VrI/lrgvEQgCX5WnnK0SdPH03OL1J60QHjtTTlR02PtsajdDQej60Gri6wA5KrHJc5YEtMQMeNMgdArUFFMQlHgHQbRHKg94rbdNABPAVsr16enAdiHLBCw00OkN/67OufCw5IkjfZAQX4meP6rOkt60HzXPPrNAfAAfQvEQewXdLP8yRgw9kWUOtQUUrrjQD5GZAzIPeN03bIAXJxcJtPAy4V7hQrdYBKxgE05jIHqAPkwQKcVOIAedL8Jp0O8HLuAGa0lc0B7IB7X6fCMQ6A2DVSMZooQ7MBNAXarAk5QO8POHXFvUOEiXeAPAAgc4A8WECSHAc4RwExAA22nOW5DuAJf40dcDW5lx1w4iS1xuKWHgU+hjxCGjFAmzJoLEgxRwoNg4ADMO7b+p7QoegAe8ugmDkAzxew5gAa94f4SVPnvQ7Q6X9TXvcX54C10WhMQ39yYeEkO+AqHROu0kFjNOK3jy+/4zc1i9G+KJB6AA2Wg9whET4TDFHiAAh+5Gvlj55FKtBQPCiWATlNf9k7B0DoC7QaBnmDYlftfoUdgPUA7IDE+jCIQahIacRF5Y/ZB4EsCat9gpZDIGtQsAPqda2pA/jBAotRU0BljO+mlgV/FkJ1Nqo70LYf5AwKOKBG3yYcYDYaayUgMQe6C2LhoNxPX2KBcKQP0LoXpAwK44D4zs3cAWoAYwHoNhqI36JuQetekDIo+nQA8iwQcEAoUB/pMAAsAN1G9Bpb1DFo3gcyBkWfRwHkWSDggFCgPtIx/uFJQPUam9QtaN4HMgZFFw7QbcZyCZKW8ebieZWvL+srwW8YESZUcyEZ41/lAKzMAG3fBxIGBRyANQPuD8gfM2DhcUAk2pTBdcDD/IzygAPuk8t/fMFwK02uLuzb98aNG2/s27fvqpOVI3Lp3p7uUGj7PpAwKNQBWHHBx8FVnwpHIy05qF7lgHt+ch87gGywNUrThdeTN/bduLHvWzfe4I8GvX33qxYV4bZIv3wgPijEAVh2wR8Pm78hzjB/PVrCuXPLDx9bNvcHyAOn+RGDshPkosD5h5Kji4v8YfF1Slnmh84u81NklzaWlvgjg6d2OX/VwA749n182WBz894k+cK+b33r92/cOElmWDi5MBqnm3whgV4nLjXPCt5QD4gOC3IAlooEpoAoByyny+fOZfcHbCzhMbO8F46eTRaTs0epWX6CND99lB86buaAlXRjkZI8Dvji59O1/Wvj8YnkxL0nvvCFP+OXk8nCieQqHRs2R+kaX0AYigMCHkBsWJTeH5C/WMQ44Fi6/Na5c+b+gHSdRlbuEVo8m5w9e/6h83L3CDuAHzRvO4Atg9014YC1NRrm8doJ8sDJkyfkha8Vy50C4xFfJx4Uug02CAyM0vsDshebGg7A/QHpOp4/z2ysrG+syNXCKgewoMhRgGf5/ZubozHfG/D6wkm5RYAdwHcKjPcPzgETHoA6NMrvD8i/RiAn3gFv4f4AGuYjchRgrpMbVo5cpyV2AN9C8DA74Ng5DooDaM/JUYAFRe4H0snefWEHvM7/7k3uJUtQuY9qiaGgYy9AGRxV9wdMTAF15oBjcn/AhkwFmQVoiW8a4AdQ00nA+vLyBXbAW3QuSGeCPgdYNw1s6T0E+cuI7xIgE1yld4lkgb/b9W4UGgwDH/+S84AgEQ5oTfQ+o2nA4Rc/gsCcWIbpgGhcB3xk10cG/Ms2UJo4QHc3VmdLcQ4Y8nQ7UBo4ALt6KPsavTFAnRPL3AG3OvUd8Ens6rkDbg5aOKCXnV3dkGTkQJ0TS3MHPHJbH98Uisaw5gMZBqhzYvE7wNwYwK9/C82QzwH8tLkpg5bmDpgeJXPA6nbK3yr96Z/rKkhyB7z3OLQpgqaw5gMZBqhzYgk7gK8KnrqcfrfwHSI9OwADjBUfmpABdU4sYQfIJYFLzkNmGNsBj0KbLhWjis4YoM6JJegAuTHg1KX0UngOSB7p4UygEvTFAHVOLCEHyFXBbTkP+K4qwJ4DHoE2U9AZAHFONCEHyI0BbIPtkjPBzw1hh6MzAOKcaAIOwI0Bl+ndoDsFDNwB0ObEEz4TDDBoB0CaU4M2Drjtla52uVSH5bpIWQXKnDrUdUCSOeCR294b3Occx2IMUh+D9VqgKAFhTi0aOIDBPvfvdYSiRwTpCrR4UG5ugIbUd4ALZBtEAMQykKlAi6dpuTlMmv4/UxSytBFpDXMAAAAASUVORK5CYII=" width="513" height="171" class="img_ev3q"></p>
<p>If you want to add a new color, we also have a full color picker. This thing is awesome - my favorite part is the eye dropper that lets you choose colors in other applications.</p>
<p><img decoding="async" loading="lazy" alt="The CSS Color Picker" src="https://jbeckwith.com/assets/images/wp_color_picker-d11639b0a8ac08b3c78eff3bdd873d73.png" width="522" height="411" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="php-code-completion">PHP Code Completion<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#php-code-completion" class="hash-link" aria-label="Direct link to PHP Code Completion" title="Direct link to PHP Code Completion" translate="no">​</a></h3>
<p>When you're ready to start diving into PHP, we include a fancy new PHP editor. It provides code completion with documentation from php.net, and a lot of other little niceties that make writing PHP easier:
<img decoding="async" loading="lazy" alt="PHP Code Completion" src="https://jbeckwith.com/assets/images/wp_php_intellisense-a22870df8c51177a31338e0fc90c05ec.png" width="705" height="259" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="wordpress-code-completion">WordPress Code Completion<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#wordpress-code-completion" class="hash-link" aria-label="Direct link to WordPress Code Completion" title="Direct link to WordPress Code Completion" translate="no">​</a></h3>
<p>So you've written some PHP, but now you want to start using the built-in functions available in WordPress. We worked with the WordPress community to come up with a list of supported functions, along with documentation on how they work. Any open source application in the gallery can provide this kind of experience:
<img decoding="async" loading="lazy" alt="WordPress specific Code Completion" src="https://jbeckwith.com/assets/images/wp_intellisense-f29f93a95051985f337608596cf0b920.png" width="728" height="224" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="mysql-database-editor">MySQL Database Editor<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#mysql-database-editor" class="hash-link" aria-label="Direct link to MySQL Database Editor" title="Direct link to MySQL Database Editor" translate="no">​</a></h3>
<p>If you need to make changes directly to the database, WebMatrix has a full featured MySQL editor built right into the product. You can create tables, manage keys, or add data right through the UI. No command line needed.
<img decoding="async" loading="lazy" alt="MySQL Database Manager" src="https://jbeckwith.com/assets/images/wp_mysql-158789f54a3ba21d8483e13f3c557ba2.png" width="786" height="385" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="remote-editing">Remote Editing<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#remote-editing" class="hash-link" aria-label="Direct link to Remote Editing" title="Direct link to Remote Editing" translate="no">​</a></h3>
<p>If you need to make edits to a live running site, we can do that to. Just enter your connection information (FTP or Web Deploy), and you can start editing your files without dealing with a FTP client:
<img decoding="async" loading="lazy" alt="Open a remote site" src="https://jbeckwith.com/assets/images/wp_start_remote-aa3597746fd3c9e4825698462671777c.png" width="508" height="359" class="img_ev3q"></p>
<p>After you make your changes, just save the file to automatically upload it to your server:
<img decoding="async" loading="lazy" alt="Edit files remotely" src="https://jbeckwith.com/assets/images/wp_remote_code-9b48537a9094fd2f83591c9714e32d7a.png" width="548" height="387" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="easy-publishing">Easy Publishing<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#easy-publishing" class="hash-link" aria-label="Direct link to Easy Publishing" title="Direct link to Easy Publishing" translate="no">​</a></h3>
<p>When you're ready to publish your application, you have the choice of using FTP or Web Deploy. If you use Web Deploy, we can even publish your database automatically along with the files in your WordPress site. When you make subsequent publish calls, only the changed files are published:</p>
<p><img decoding="async" loading="lazy" alt="Easy Publishing" src="https://jbeckwith.com/assets/images/wp_publish-7b97b9d68cdcbda8ca0cc35c7f8cb7ba.png" width="724" height="522" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="more-information">More Information<a href="https://jbeckwith.com/blog/2012/06/09/wordpress-and-webmatrix#more-information" class="hash-link" aria-label="Direct link to More Information" title="Direct link to More Information" translate="no">​</a></h3>
<p>If you would like some more information to help you get started, check out some of these links:</p>
<ul>
<li class=""><a href="http://bit.ly/LG7gs8" target="_blank" rel="noopener noreferrer" class="">WebMatrix on Microsoft.com</a></li>
<li class=""><a href="https://twitter.com/#!/webmatrix" target="_blank" rel="noopener noreferrer" class="">WebMatrix on Twitter</a></li>
<li class=""><a href="https://github.com/MicrosoftWebMatrix" target="_blank" rel="noopener noreferrer" class="">WebMatrix on GitHub</a></li>
<li class=""><a href="http://webmatrix.uservoice.com/" target="_blank" rel="noopener noreferrer" class="">WebMatrix on UserVoice</a></li>
<li class=""><a href="http://www.microsoft.com/Web/webmatrix/optimize.aspx" target="_blank" rel="noopener noreferrer" class="">WebMatrix and Open Source Applications</a></li>
<li class=""><a href="http://vishaljoshi.blogspot.com/2012/06/announcing-webmatrix-2-rc.html" target="_blank" rel="noopener noreferrer" class="">Vishal Joshi's blog post</a></li>
</ul>
<p>Happy Coding!</p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="featured" term="featured"/>
        <category label="mysql" term="mysql"/>
        <category label="php" term="php"/>
        <category label="programming" term="programming"/>
        <category label="webmatrix" term="webmatrix"/>
        <category label="wordpress" term="wordpress"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Node.js meet WebMatrix 2]]></title>
        <id>https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2</id>
        <link href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2"/>
        <updated>2012-06-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[After months of hard work by the WebMatrix team, it's exciting to introduce the release candidate of WebMatrix 2. WebMatrix 2 includes tons of new features, but today I want to give an overview of the work we've done to enable building applications with Node.js]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="WebMatrix 2 + Node.js = love" src="https://jbeckwith.com/assets/images/title-header-f8771188927aea2c4de7236e504b444c.png" width="556" height="292" class="img_ev3q"></p>
<p>After months of hard work by the WebMatrix team, it's exciting to introduce the release candidate of WebMatrix 2. WebMatrix 2 includes tons of new features, but today I want to give an overview of the work we've done to enable building applications with Node.js.</p>
<p>If you want to skip all of this and just get a download link (it's free!), <a href="http://bit.ly/LG7gs8" target="_blank" rel="noopener noreferrer" class="">here you go</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-far-we-have-come">How far we have come<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#how-far-we-have-come" class="hash-link" aria-label="Direct link to How far we have come" title="Direct link to How far we have come" translate="no">​</a></h2>
<p>Less than a year ago, I was working at Carnegie Mellon University, trying to use Node.js with ASP.NET for real time components of our online learning environment. Running Linux inside of our customers' data centers was a non-starter, and running a production system in cygwin was even less ideal. Developing node on Windows wasn't exactly easy either - if you managed to get node running, getting NPM to work was near impossible. Using node in an environment favorable to Windows was more than an up hill battle.</p>
<p>In the last 12 months since I've joined Microsoft, we've seen various partnerships between Joyent and Microsoft, resulting in new releases of node and npm to support Windows, and a <a href="https://www.windowsazure.com/en-us/develop/nodejs/" target="_blank" rel="noopener noreferrer" class="">commitment to Node on Windows Azure</a>. We've worked together to build a better experience for developers, IT administrators, and ultimately, the users who use our systems.</p>
<p>One of the results of that work is a vastly improved experience for building applications with Node.js on Windows Azure. Glenn Block on the SDK team has done a <a href="http://codebetter.com/glennblock/2012/06/07/windowsazure-just-got-a-lot-friendlier-to-node-js-developers/" target="_blank" rel="noopener noreferrer" class="">fabulous write up</a> on the ways Microsoft is making Azure a great place for Node.js developers. As our favorite VP Scott Guthrie says on his blog, <a href="http://weblogs.asp.net/scottgu/archive/2012/06/07/meet-the-new-windows-azure.aspx" target="_blank" rel="noopener noreferrer" class="">meet the new Windows Azure</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="enter-webmatrix-2">Enter WebMatrix 2<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#enter-webmatrix-2" class="hash-link" aria-label="Direct link to Enter WebMatrix 2" title="Direct link to Enter WebMatrix 2" translate="no">​</a></h3>
<p>Today, getting started with node.js is a relatively simple task. You install node, npm (which is now bundled with the node installers), and get started with your favorite text editor. There are infinite possibilities, and limitless configurations for managing projects, compiling CoffeeScript &amp; LESS, configuring your production settings, and deploying your apps. WebMatrix 2 sets out to provide another way to build node.js apps: everything you need to build great apps is one place.</p>
<p><img decoding="async" loading="lazy" alt="Welcome to WebMatrix" src="https://jbeckwith.com/assets/images/splash-56f29e920bf00167bd02bc4aada44335.png" width="800" height="550" class="img_ev3q"></p>
<p>WebMatrix 2 is first and foremost designed for building web applications. From the start screen, you can create applications using pre-built templates, or install common open source applications from the Web Gallery. The current set of templates support creating applications with <a href="http://nodejs.org/" target="_blank" rel="noopener noreferrer" class="">Node.js</a>, <a href="http://php.net/" target="_blank" rel="noopener noreferrer" class="">PHP</a>, and (of course) <a href="http://www.asp.net/web-pages" target="_blank" rel="noopener noreferrer" class="">ASP.NET Web Pages</a>. Out of the box, WebMatrix 2 includes three templates for Node.js:</p>
<ul>
<li class="">Empty Node.js Site</li>
<li class="">Express Site</li>
<li class="">Express Starter Site</li>
</ul>
<p>The empty site provides a very basic example of using an http server - the same sample that's available on <a href="http://nodejs.org/" target="_blank" rel="noopener noreferrer" class="">nodejs.org</a>. The Express Site is a basic application generated using the scaffolding tool in the Node.js framework <a href="http://expressjs.com/" target="_blank" rel="noopener noreferrer" class="">express</a>. The Node Starter Site is where things start to get interesting. This boilerplate is <a href="https://github.com/MicrosoftWebMatrix/ExpressStarter" target="_blank" rel="noopener noreferrer" class="">hosted on GitHub</a>, and shows how to implement sites that include parent/child layouts with jade, LESS css, logins with Twitter and Facebook, mobile layouts, and captcha. When you create a new application using any of these templates, WebMatrix 2 is going to ensure node, npm, and IISNode are installed on your system. If not, it will automatically install any missing dependencies. This feature is also particularly useful if you are building PHP/MySQL applications on Windows.</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix installs node, npm, and iisnode" src="https://jbeckwith.com/assets/images/dependencies-1056e7d7b62bab91768cd6bddeca6ad9.png" width="724" height="486" class="img_ev3q"></p>
<p>The end result of the Node Starter Site is a fully functional application that includes Express, Jade, LESS, chat with socket.io, logins with EveryAuth, and mobile support with jQuery Mobile:</p>
<p><img decoding="async" loading="lazy" alt="The node starter template" src="https://jbeckwith.com/assets/images/template-7abfd16ce62b2451b6a840ffec74902d.png" width="1028" height="558" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="intellisense-for-nodejs">IntelliSense for Node.js<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#intellisense-for-nodejs" class="hash-link" aria-label="Direct link to IntelliSense for Node.js" title="Direct link to IntelliSense for Node.js" translate="no">​</a></h3>
<p>One of the goals of WebMatrix 2 is reduce the barrier of entry for developers getting started with Node.js. One of the ways to do that is to provide IntelliSense for the core modules on which all applications are built. The documentation we use is actually built from the docs on the <a href="http://nodejs.org/api/" target="_blank" rel="noopener noreferrer" class="">node.js docs site</a>.</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix provides IntelliSense that makes it easier to get started" src="https://jbeckwith.com/assets/images/moduleIntelliSense-10ea6e20d7d5d5864c673ea210e318f5.png" width="521" height="350" class="img_ev3q"></p>
<p>In addition to providing IntelliSense for core Node.js modules, WebMatrix 2 also provides code completion for your own JavaScript code, and third party modules installed through NPM. There are infinite ways to build your application, and the NPM gallery recently <a href="https://twitter.com/JavaScriptDaily/status/203878468205817857" target="_blank" rel="noopener noreferrer" class="">surpassed 10,000 entries</a>. As developers start building more complex applications, it can be difficult (or even intimidating) to get started. WebMatrix 2 is making it easier to deal with open source packages:</p>
<p><img decoding="async" loading="lazy" alt="Use third party modules with code completion" src="https://jbeckwith.com/assets/images/thirdpartyintellisense-69584f128545ae1f27c4caad8dd8c1cb.png" width="581" height="393" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="support-for-jade--ejs">Support for Jade &amp; EJS<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#support-for-jade--ejs" class="hash-link" aria-label="Direct link to Support for Jade &amp; EJS" title="Direct link to Support for Jade &amp; EJS" translate="no">​</a></h3>
<p>To build a truly useful tool for building Node.js web applications, we decided to provide first class editors for <a href="http://jade-lang.com/" target="_blank" rel="noopener noreferrer" class="">Jade</a> and <a href="http://embeddedjs.com/" target="_blank" rel="noopener noreferrer" class="">EJS</a>. WebMatrix 2 provides syntax highlighting, HTML validation, code outlining, and auto-completion for Jade and EJS.</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix has syntax highlighting for Jade" src="https://jbeckwith.com/assets/images/jade-5beb942975a0043f262bf6b8f84f8b9e.png" width="624" height="395" class="img_ev3q"></p>
<p>If you're into the whole angle bracket thing, the experience in EJS even better, since it's based off of our advanced HTML editor:</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix has IntelliSense for EJS" src="https://jbeckwith.com/assets/images/ejs-ed0f25e80e914f5d506458ec5af872a6.png" width="655" height="475" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-best-less-editor-on-the-planet">The best LESS editor on the planet<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#the-best-less-editor-on-the-planet" class="hash-link" aria-label="Direct link to The best LESS editor on the planet" title="Direct link to The best LESS editor on the planet" translate="no">​</a></h3>
<p>So I'll admit it - I'm a bit of a CSS pre-processor geek. I don't write CSS because I love it, but because I need to get stuff done, and I want to write as little of it as possible. Tools like <a href="http://lesscss.org/" target="_blank" rel="noopener noreferrer" class="">LESS</a> and <a href="http://sass-lang.com/" target="_blank" rel="noopener noreferrer" class="">Sass</a> provide missing features for programmers in CSS like variables, mixins, nesting, and built in common functions.</p>
<p><img decoding="async" loading="lazy" alt="Write LESS with validation, formatting, and IntelliSense" src="https://jbeckwith.com/assets/images/less-c838c0a3163fd176a0543d710cb0b131.png" width="442" height="289" class="img_ev3q"></p>
<p>The LESS editor in WebMatrix not only provides syntax highlighting, but also provides LESS specific validation, IntelliSense for variables and mixins, and LESS specific formatting. Most node developers are going to process their LESS on the server using the npm module, but if you want to compile LESS locally, you can use the <a href="http://extensions.webmatrix.com/packages/OrangeBits/" target="_blank" rel="noopener noreferrer" class="">Orange Bits compiler</a> to compile your CSS at design time.</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix provides syntax highlighting for Sass" src="data:image/png;base64,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" width="263" height="205" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="coffeescript-editor">CoffeeScript Editor<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#coffeescript-editor" class="hash-link" aria-label="Direct link to CoffeeScript Editor" title="Direct link to CoffeeScript Editor" translate="no">​</a></h3>
<p>In the same way LESS and Sass make it easier to write CSS, <a href="http://coffeescript.org/" target="_blank" rel="noopener noreferrer" class="">CoffeeScript</a> simplifies the way you write JavaScript. WebMatrix 2 provides syntax highlighting, code outlining, and completion that simplifies the editing experience. If you want to use CoffeeScript without compiling it on the server, you can use the <a href="http://extensions.webmatrix.com/packages/OrangeBits/" target="_blank" rel="noopener noreferrer" class="">Orange Bits compiler</a> to compile your CoffeeScript into JavaScript at design time.</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix and CoffeeScript" src="data:image/png;base64,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" width="425" height="396" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="mobile-emulators">Mobile Emulators<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#mobile-emulators" class="hash-link" aria-label="Direct link to Mobile Emulators" title="Direct link to Mobile Emulators" translate="no">​</a></h3>
<p>Designing applications for mobile can't be an afterthought. WebMatrix 2 is trying to make this easier in a couple of ways. First - the visual templates (in this case the Node Starter Template) is designed taking advantage of responsive layouts in the main StyleSheet:</p>
<ul>
<li class=""><a href="https://github.com/MicrosoftWebMatrix/ExpressStarter/blob/master/public/stylesheets/style.less" target="_blank" rel="noopener noreferrer" class="">styles.less</a></li>
</ul>
<p>This is great if you don't need to change the content of your site, but is lacking for more complex scenarios. To get around that, the node starter template uses a piece of connect middleware to detect if the user is coming from a mobile device, and sends them to a mobile layout based on jQuery Mobile (more on this in another post). For individual views, there is a convention based system that allows you to create <code>[viewName]_mobile.jade</code> views which are only loaded on mobile devices.</p>
<p>It gets even better. What if you need to see what your site will look like in various browsers and mobile devices? WebMatrix 2 provides an extensibility model that allows you to add mobile and desktop browsers to the run menu:</p>
<p><img decoding="async" loading="lazy" alt="WebMatrix shows all of the browsers and emulators on your system" src="https://jbeckwith.com/assets/images/emulators-b59f57fbc429fa43c6737d2c4fe5ff52.png" width="575" height="523" class="img_ev3q"></p>
<p>Today, we offer a Windows Phone emulator, and iPhone / iPad simulators. In the future we're looking for people to build support for other emulators <em>coughs</em> android <em>coughs</em>, and even build bridges to online browser testing applications:</p>
<p><img decoding="async" loading="lazy" alt="Test your websites on the iPhone simulator" src="https://jbeckwith.com/assets/images/iphone-4e848ba294580213f620976d7033dc94.png" width="365" height="710" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="extensions--open-source">Extensions &amp; Open Source<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#extensions--open-source" class="hash-link" aria-label="Direct link to Extensions &amp; Open Source" title="Direct link to Extensions &amp; Open Source" translate="no">​</a></h3>
<p>A code editing tool is only as valuable as the developers that commit to the platform. We want to achieve success with everyone, and grow together. As part of that goal, we've opened up an extensibility model that allows developers to build custom extensions and share them with other developers. The extension gallery is available online (more on this to come) at <a href="http://extensions.webmatrix.com/" target="_blank" rel="noopener noreferrer" class="">http://extensions.webmatrix.com</a>. We're planning to move a bunch of these extensions into GitHub, and the NodePowerTools extension is the first one to go open source:</p>
<ul>
<li class=""><a href="https://github.com/MicrosoftWebMatrix/NodePowerTools" target="_blank" rel="noopener noreferrer" class="">Node Power Tools</a></li>
<li class=""><a href="https://github.com/JustinBeckwith/OrangeBits" target="_blank" rel="noopener noreferrer" class="">OrangeBits Compiler</a></li>
</ul>
<p>In the coming months you'll start to see more extensions from Microsoft, and more open source.</p>
<p><img decoding="async" loading="lazy" alt="Build extensions and share them on the extension gallery" src="https://jbeckwith.com/assets/images/extension-gallery-fed6334ed7e0cda9e9a3e5bb2b311cb0.png" width="998" height="550" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="everyone-worked-together">Everyone worked together<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#everyone-worked-together" class="hash-link" aria-label="Direct link to Everyone worked together" title="Direct link to Everyone worked together" translate="no">​</a></h3>
<p>I want to make sure I thank everyone who helped make this release happen, including the WebMatrix team, Glenn Block, Claudio Caldato, our Node Advisory board, Isaac Schlueter, and everyone at Joyent. For more information, please visit:</p>
<ul>
<li class=""><a href="http://bit.ly/LG7gs8" target="_blank" rel="noopener noreferrer" class="">WebMatrix on Microsoft.com</a></li>
<li class=""><a href="https://twitter.com/#!/webmatrix" target="_blank" rel="noopener noreferrer" class="">WebMatrix on Twitter</a></li>
<li class=""><a href="https://github.com/MicrosoftWebMatrix" target="_blank" rel="noopener noreferrer" class="">WebMatrix on GitHub</a></li>
<li class=""><a href="http://webmatrix.uservoice.com/" target="_blank" rel="noopener noreferrer" class="">WebMatrix on UserVoice</a></li>
<li class=""><a href="http://www.microsoft.com/web/post/how-to-use-the-nodejs-starter-template-in-webmatrix" target="_blank" rel="noopener noreferrer" class="">WebMatrix and Node on Microsoft.com</a></li>
<li class=""><a href="http://codebetter.com/glennblock/2012/06/07/windowsazure-just-got-a-lot-friendlier-to-node-js-developers/" target="_blank" rel="noopener noreferrer" class="">Windows Azure just got a lot friendlier to node.js developers</a></li>
<li class=""><a href="http://vishaljoshi.blogspot.com/2012/06/announcing-webmatrix-2-rc.html" target="_blank" rel="noopener noreferrer" class="">Vishal Joshi's blog post</a></li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="enjoy">Enjoy<a href="https://jbeckwith.com/blog/2012/06/07/node-js-meet-webmatrix-2#enjoy" class="hash-link" aria-label="Direct link to Enjoy" title="Direct link to Enjoy" translate="no">​</a></h4>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="coffeescript" term="coffeescript"/>
        <category label="featured" term="featured"/>
        <category label="less" term="less"/>
        <category label="node" term="node"/>
        <category label="programming" term="programming"/>
        <category label="projects" term="projects"/>
        <category label="sass" term="sass"/>
        <category label="webmatrix" term="webmatrix"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building a user map with SignalR and Bing]]></title>
        <id>https://jbeckwith.com/blog/2011/10/12/building-a-user-map-with-signalr-and-bing</id>
        <link href="https://jbeckwith.com/blog/2011/10/12/building-a-user-map-with-signalr-and-bing"/>
        <updated>2011-10-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Building asynchronous real time apps with bidirectional communication has traditionally been a very difficult thing to do. HTTP was originally designed to speak in terms of requests and responses, long before concepts of rich media, social integration, and real time communication were considered staples of modern web development. Over the years, various solutions have been hacked together to solve this problem. You can use plugins like flash or silverlight to make a true socket connection on your behalf - but not all clients support plugins. You can use long polling to manage multiple connections via HTTP - but this can be tricky to implement, and can eat up system resources. The Web Socket standard promises to give web developers a first class socket connection, but browser support is spotty and inconsistent.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://signalrmap.apphb.com/" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" alt="Building a user map with SignalR and Bing" src="https://jbeckwith.com/assets/images/signalrheader-772c5600b012630e9cea5797616e20ee.png" title="Building a user map with SignalR and Bing" width="430" height="290" class="img_ev3q"></a></p>
<p>Building asynchronous real time apps with bidirectional communication has traditionally been a very difficult thing to do. HTTP was originally designed to speak in terms of requests and responses, long before concepts of rich media, social integration, and real time communication were considered staples of modern web development. Over the years, various solutions have been hacked together to solve this problem. You can use plugins like flash or silverlight to make a true socket connection on your behalf - but not all clients support plugins. You can use long polling to manage multiple connections via HTTP - but this can be tricky to implement, and can eat up system resources. The <a href="http://dev.w3.org/html5/websockets/" target="_blank" rel="noopener noreferrer" class="">Web Socket standard</a> promises to give web developers a first class socket connection, but browser support is spotty and inconsistent.</p>
<p>Various tools across multiple stacks have been release to solve this problem, but in this post I would like to talk about the first real asynchronous client/server package for ASP.NET: <a href="https://github.com/SignalR/SignalR" target="_blank" rel="noopener noreferrer" class="">SignalR</a>. SignalR allows .NET developers to change the way we think about client/server messaging: instead of worrying about implementation details of web sockets, we can focus on the way communication flows across the various components of our applications.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="this-sounds-familiar-socketio-with-nodejs">This sounds familiar: socket.io with node.js<a href="https://jbeckwith.com/blog/2011/10/12/building-a-user-map-with-signalr-and-bing#this-sounds-familiar-socketio-with-nodejs" class="hash-link" aria-label="Direct link to This sounds familiar: socket.io with node.js" title="Direct link to This sounds familiar: socket.io with node.js" translate="no">​</a></h2>
<p>Over the last year or so, <a href="http://nodejs.org/" target="_blank" rel="noopener noreferrer" class="">node.js</a> has burst onto the scene as a popular stack for building highly asynchronous applications. The event driven model of JavaScript, paired with a community of inventive developers, led to a platform well suited for these needs. The package <a href="http://socket.io/" target="_blank" rel="noopener noreferrer" class="">socket.io</a> provides what I have found to be the missing piece in the comet puzzle: a front and back end framework that just makes sockets over the web work. No more building flash applications to attempt opening connections over various ports. No more poorly implemented long polling solutions. Most importantly, socket.io made web sockets just plain easy to use:</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">script</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">src</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">/socket.io/socket.io.js</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token script"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">script</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">script</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">  </span><span class="token script language-javascript keyword" style="color:#00009f">var</span><span class="token script language-javascript"> socket </span><span class="token script language-javascript operator" style="color:#393A34">=</span><span class="token script language-javascript"> io</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">connect</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript string" style="color:#e3116c">'http://localhost'</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">  socket</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">on</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript string" style="color:#e3116c">'news'</span><span class="token script language-javascript punctuation" style="color:#393A34">,</span><span class="token script language-javascript"> </span><span class="token script language-javascript keyword" style="color:#00009f">function</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript parameter">data</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">    </span><span class="token script language-javascript console class-name">console</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">log</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript">data</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">    socket</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">emit</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript string" style="color:#e3116c">'my other event'</span><span class="token script language-javascript punctuation" style="color:#393A34">,</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">{</span><span class="token script language-javascript literal-property property" style="color:#36acaa">my</span><span class="token script language-javascript operator" style="color:#393A34">:</span><span class="token script language-javascript"> </span><span class="token script language-javascript string" style="color:#e3116c">'data'</span><span class="token script language-javascript punctuation" style="color:#393A34">}</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:#393A34">}</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">script</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></div></code></pre></div></div>
<p>Node.js and socket.io paved the way for a series of new tools and frameworks across multiple stacks that enable developers to have a first class client/server messaging experience. Node.js and socket.io are wonderful tools - but let's get back to focusing on SignalR.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="two-ways-to-build-apps-with-signalr">Two ways to build apps with SignalR<a href="https://jbeckwith.com/blog/2011/10/12/building-a-user-map-with-signalr-and-bing#two-ways-to-build-apps-with-signalr" class="hash-link" aria-label="Direct link to Two ways to build apps with SignalR" title="Direct link to Two ways to build apps with SignalR" translate="no">​</a></h3>
<p>There are two ways you can go about setting up the server for SignalR. If you want a low level experience, you can add a 'PersistentConnection' class along with a custom route. This will give you basic messaging capabilities, suitable for many apps. Straight from the <a href="https://github.com/SignalR/SignalR" target="_blank" rel="noopener noreferrer" class="">SignalR github</a>, here is an example:</p>
<div class="language-cs codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cs codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">SignalR</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MyConnection</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">PersistentConnection</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">protected</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">override</span><span class="token plain"> </span><span class="token return-type class-name">Task</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">OnReceivedAsync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">string</span><span class="token plain"> clientId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name keyword" style="color:#00009f">string</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// Broadcast data to all clients</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> Connection</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Broadcast</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>This works well if you're dealing with simple messaging - the other model SignalR supports is the 'hub' model. This is where things start to get interesting. Using hubs, you can invoke client side functions from the server, and server side functions from the client. Here's another example from the documentation:</p>
<p>Here is the server:</p>
<div class="language-cs codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cs codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Chat</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">Hub</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Send</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name keyword" style="color:#00009f">string</span><span class="token plain"> message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// Call the addMessage method on all clients</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Clients</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">addMessage</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>And the client:</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">script</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text/javascript</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">  </span><span class="token script language-javascript function" style="color:#d73a49">$</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript keyword" style="color:#00009f">function</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">   </span><span class="token script language-javascript comment" style="color:#999988;font-style:italic">// Proxy created on the fly</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">   </span><span class="token script language-javascript keyword" style="color:#00009f">var</span><span class="token script language-javascript"> chat </span><span class="token script language-javascript operator" style="color:#393A34">=</span><span class="token script language-javascript"> $</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript property-access">connection</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript property-access">chat</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">   </span><span class="token script language-javascript comment" style="color:#999988;font-style:italic">// Declare a function on the chat hub so the server can invoke it</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">   chat</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method-variable function-variable method function property-access" style="color:#d73a49">addMessage</span><span class="token script language-javascript"> </span><span class="token script language-javascript operator" style="color:#393A34">=</span><span class="token script language-javascript"> </span><span class="token script language-javascript keyword" style="color:#00009f">function</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript parameter">message</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">     </span><span class="token script language-javascript function" style="color:#d73a49">$</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript string" style="color:#e3116c">'#messages'</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">append</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript string" style="color:#e3116c">'&lt;li&gt;'</span><span class="token script language-javascript">   message   </span><span class="token script language-javascript string" style="color:#e3116c">'&lt;/li&gt;'</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">   </span><span class="token script language-javascript punctuation" style="color:#393A34">}</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">   </span><span class="token script language-javascript function" style="color:#d73a49">$</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript string" style="color:#e3116c">"#broadcast"</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">click</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript keyword" style="color:#00009f">function</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">{</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">     </span><span class="token script language-javascript comment" style="color:#999988;font-style:italic">// Call the chat method on the server</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">     chat</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">send</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript function" style="color:#d73a49">$</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript string" style="color:#e3116c">'#msg'</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">val</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">       </span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">fail</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript keyword" style="color:#00009f">function</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript parameter">e</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">{</span><span class="token script language-javascript"> </span><span class="token script language-javascript function" style="color:#d73a49">alert</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript">e</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"> </span><span class="token script language-javascript punctuation" style="color:#393A34">}</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript"> </span><span class="token script language-javascript comment" style="color:#999988;font-style:italic">// Supports jQuery deferred</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">   </span><span class="token script language-javascript punctuation" style="color:#393A34">}</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">   </span><span class="token script language-javascript comment" style="color:#999988;font-style:italic">// Start the connection</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">   $</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript property-access">connection</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript property-access">hub</span><span class="token script language-javascript punctuation" style="color:#393A34">.</span><span class="token script language-javascript method function property-access" style="color:#d73a49">start</span><span class="token script language-javascript punctuation" style="color:#393A34">(</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript">  </span><span class="token script language-javascript punctuation" style="color:#393A34">}</span><span class="token script language-javascript punctuation" style="color:#393A34">)</span><span class="token script language-javascript punctuation" style="color:#393A34">;</span><span class="token script language-javascript"></span><br></div><div class="token-line" style="color:#393A34"><span class="token script language-javascript"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">script</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">msg</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">input</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">button</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">broadcast</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag punctuation" style="color:#393A34">/&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">ul</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">id</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">messages</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">ul</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></div></code></pre></div></div>
<p>I chose the high level API, because well... it's just cool. For a wonderful break down of the differences between these two methods, check out <a href="http://www.hanselman.com/blog/AsynchronousScalableWebApplicationsWithRealtimePersistentLongrunningConnectionsWithSignalR.aspx" target="_blank" rel="noopener noreferrer" class="">Scott Hanselman's post on the topic</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="lets-build-something">Lets build something<a href="https://jbeckwith.com/blog/2011/10/12/building-a-user-map-with-signalr-and-bing#lets-build-something" class="hash-link" aria-label="Direct link to Lets build something" title="Direct link to Lets build something" translate="no">​</a></h3>
<p>One of the common examples of using these frameworks is a chat room: it has all of the touch points that are otherwise difficult to implement. How do we know when someone joins the room? What about sending a message? What if I want to send a message to multiple people? This is a perfect example of how client/server messaging over the web can make our lives easier. The SignalR folks have a live sample of this application running on their <a href="http://chatapp.apphb.com/" target="_blank" rel="noopener noreferrer" class="">demo site</a>. With the chat idea done, I decided to combine two tools into one project: a user map. I want to maintain a map that uses a pushpin for every user on the page. As users come, a new pushpin will be added in their location in real time. As they leave, the pushpin will be removed. Before we dive into the code, check out the demo at <a href="http://signalrmap.apphb.com/" target="_blank" rel="noopener noreferrer" class="">http://signalrmap.apphb.com/</a>. If no one is in the room, you can slightly randomize your position by using the "random flag" at <a href="http://signalrmap.apphb.com/?random=true" target="_blank" rel="noopener noreferrer" class="">http://signalrmap.apphb.com/?random=true</a>. This will allow you to use multiple browser windows and watch the system add location push pins.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="building-the-client">Building the client<a href="https://jbeckwith.com/blog/2011/10/12/building-a-user-map-with-signalr-and-bing#building-the-client" class="hash-link" aria-label="Direct link to Building the client" title="Direct link to Building the client" translate="no">​</a></h3>
<p>The client of SignalRMap includes a Bing map, and some JavaScript to interact with the back end. I used <a href="http://www.asp.net/mvc/mvc3" target="_blank" rel="noopener noreferrer" class="">ASP.NET MVC 3</a> for this example, but this will work just fine with a web form. To start, we need to include a few script files:</p>
<div class="language-html codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-html codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token tag punctuation" style="color:#393A34">&lt;</span><span class="token tag" style="color:#00009f">script</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">charset</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">UTF-8</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">type</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">text/javascript</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag" style="color:#00009f"> </span><span class="token tag attr-name" style="color:#00a4db">src</span><span class="token tag attr-value punctuation attr-equals" style="color:#393A34">=</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag attr-value" style="color:#e3116c">http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0</span><span class="token tag attr-value punctuation" style="color:#393A34">"</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token script"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">script</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">&lt;script src="@Url.Content("~/Scripts/jquery-1.6.4.min.js")" type="text/javascript"&gt;</span><span class="token script"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">script</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">&lt;script src="@Url.Content("~/Scripts/jquery.signalR.min.js")" type="text/javascript"&gt;</span><span class="token script"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">script</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">&lt;script type="text/javascript" src="@Url.Content("~/signalr/hubs")"&gt;</span><span class="token script"></span><span class="token tag punctuation" style="color:#393A34">&lt;/</span><span class="token tag" style="color:#00009f">script</span><span class="token tag punctuation" style="color:#393A34">&gt;</span><br></div></code></pre></div></div>
<p>The first thing we are including here is the Bing Maps JavaScript SDK - this will do all of the heavy lifting for our maps. The SignalR client is dependent upon JavaScript, so we need to include it along with our SignalR reference. Finally, we include the 'hubs' functionality into our application, linking our client and server side methods.</p>
<p>After including our scripts, connecting to a hub is crazy awesome easy:</p>
<div class="language-js codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-js codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// create the connection to our hub</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> mapHub </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> $</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">connection</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">mapHub</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// define some javascript methods the server side hub can invoke</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// add a new client to the map</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">mapHub</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">addClient</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">client</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">addClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">client</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">centerMap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> pins </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getPushPins</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">$</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">#userCount</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">quot</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">html</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">pins</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">length</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// start the hub</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">$</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">connection</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">hub</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">start</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// after the hub has started, get the current location from the browser</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token dom variable" style="color:#36acaa">navigator</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">geolocation</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">getCurrentPosition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">position</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// create the map element on the page</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token function" style="color:#d73a49">mappit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">position</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">// notify the server a new user has joined the party</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> coords </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> isRandom </span><span class="token operator" style="color:#393A34">?</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">createRandomPosition</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">position</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> position</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">coords</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> message </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token string-property property" style="color:#36acaa">'user'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string-property property" style="color:#36acaa">'location'</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">latitude</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> coords</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">latitude</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token literal-property property" style="color:#36acaa">longitude</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> coords</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">longitude</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  mapHub</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<p>There are a few things going on here. First, we reference our connection to the hub created on the server (note: the connection has not been established yet). Notice the mapHub.addClient method - this method will be exposed in a way such that it can be invoked from the server. <em>scratches head</em> - this is a neat concept. After defining methods which can be invoked from the server, we start the connection to the hub. Once the connection is established, we get the browser's current location, and send that location back to the server. That's about it. Remember how simple it was to use socket.io? Here we have the same experience. There's a little more client script here to handle managing the map component. For the full client source for the application, check out my <a href="https://github.com/JustinBeckwith/SignalRMap" target="_blank" rel="noopener noreferrer" class="">github</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="server-side-code">Server side code<a href="https://jbeckwith.com/blog/2011/10/12/building-a-user-map-with-signalr-and-bing#server-side-code" class="hash-link" aria-label="Direct link to Server side code" title="Direct link to Server side code" translate="no">​</a></h3>
<p>As mentioned above, I chose to take the 'hubs' route for my application. One of the nice things about using a hub is that it doesn't require any custom routing - just create a class that extends 'Hub', and you're set. In this example, I'm storing a persistent list of the clients connected to the application (obviously, this method will only work with a single web server). As users show up at the site, they send their current position to the server. The new MapClient is broadcasted to all of the connected clients, and the new client is given the master list of clients:</p>
<div class="language-cs codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-cs codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">System</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">System</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Collections</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Generic</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">System</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Linq</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">System</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Web</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">using</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">SignalR</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">.</span><span class="token namespace" style="opacity:0.7">Hubs</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">namespace</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">SignalRMap</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MapHub</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token type-list class-name">Hub</span><span class="token type-list punctuation" style="color:#393A34">,</span><span class="token type-list"> </span><span class="token type-list class-name">IDisconnect</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">readonly</span><span class="token plain"> Dictionary</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">lt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> MapClient</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">gt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> _clients </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> Dictionary</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">lt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token keyword" style="color:#00009f">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> MapClient</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">gt</span><span class="token punctuation" style="color:#393A34">;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Join</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">MapClient</span><span class="token plain"> message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   _clients</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Add</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ClientId</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   Clients</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">addClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">message</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token keyword" style="color:#00009f">this</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Caller</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">addClients</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">_clients</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ToArray</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Disconnect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token class-name">MapClient</span><span class="token plain"> client </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> _clients</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ClientId</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   _clients</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Remove</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ClientId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   Clients</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">removeClient</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">client</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/// model class for the join message. I tried to use dynamic here, but it didn't work.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token comment" style="color:#999988;font-style:italic">/// &amp;lt;/summary&amp;gt;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">MapClient</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">string</span><span class="token plain"> clientId </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">set</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name">Location</span><span class="token plain"> location </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">set</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Location</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">float</span><span class="token plain"> latitude </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">set</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token return-type class-name keyword" style="color:#00009f">float</span><span class="token plain"> longitude </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">get</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">set</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>And that's it! SignalR figured out what types of communication my browser supports, managed the tunnel, and just made the connection work. Enjoy!</p>
<ul>
<li class=""><a href="http://signalrmap.apphb.com/?random=true" target="_blank" rel="noopener noreferrer" class="">View the demo</a></li>
<li class=""><a href="https://github.com/JustinBeckwith/SignalRMap" target="_blank" rel="noopener noreferrer" class="">Download the source code</a></li>
<li class=""><a href="https://github.com/SignalR/SignalR" target="_blank" rel="noopener noreferrer" class="">SignalR on GitHub</a></li>
<li class=""><a href="http://www.bingmapsportal.com/ISDK/AjaxV7" target="_blank" rel="noopener noreferrer" class="">Bing Maps SDK</a></li>
</ul>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="net" term="net"/>
        <category label="bing" term="bing"/>
        <category label="featured" term="featured"/>
        <category label="javascript" term="javascript"/>
        <category label="programming" term="programming"/>
        <category label="signalr" term="signalr"/>
        <category label="aspnet" term="aspnet"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Using MSBuild to deploy your AppFabric Application]]></title>
        <id>https://jbeckwith.com/blog/2011/07/20/using-msbuild-to-deploy-your-appfabric-application</id>
        <link href="https://jbeckwith.com/blog/2011/07/20/using-msbuild-to-deploy-your-appfabric-application"/>
        <updated>2011-07-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[As the hosting of applications moves from our local staging environments to the cloud, one of the areas that needs to improve is the ability to include deployment in our automated build processes. Using the June CTP AppFabric bits, Visual Studio does an excellent job of enabling developers to design, build, and deploy AppFabric applications. However, the current tools do not provide a way to integrate these tools into a standard, repeatable build process. The goal of this post is to outline the steps necessary to integrate automated AppFabric deployment into your build process, and show off some of the REST API features we’ve built into the Application Manager.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Using MSBuild to deploy your AppFabric Application" src="https://jbeckwith.com/assets/images/azure3-81ad07bc3738114601b36c1de0fb3d7d.png" title="azure3" width="300" height="300" class="img_ev3q"></p>
<p>I wrote a blog post for the MSDN AppFabric Blog!</p>
<p><a href="http://blogs.msdn.com/b/appfabric/archive/2011/07/20/using-msbuild-to-deploy-your-appfabric-application.aspx" target="_blank" rel="noopener noreferrer" class="">Using MSBuild to deploy your AppFabric Application</a></p>]]></content>
        <author>
            <name>Justin Beckwith</name>
            <email>justin.beckwith@gmail.com</email>
            <uri>https://jbeckwith.com</uri>
        </author>
        <category label="appfabric" term="appfabric"/>
        <category label="automated-builds" term="automated-builds"/>
        <category label="azure" term="azure"/>
        <category label="cloud" term="cloud"/>
        <category label="microsoft" term="microsoft"/>
        <category label="msbuild" term="msbuild"/>
        <category label="azure" term="azure"/>
    </entry>
</feed>