<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Tyler Finethy on Medium]]></title>
        <description><![CDATA[Stories by Tyler Finethy on Medium]]></description>
        <link>https://medium.com/@tylfin?source=rss-e95ef4be7a2e------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*0o7_rNc5q-AebMvK48usyQ.jpeg</url>
            <title>Stories by Tyler Finethy on Medium</title>
            <link>https://medium.com/@tylfin?source=rss-e95ef4be7a2e------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 08 Apr 2026 18:29:54 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@tylfin/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[That Time Facebook Vanished]]></title>
            <link>https://medium.com/@tylfin/that-time-facebook-vanished-1e742f917185?source=rss-e95ef4be7a2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/1e742f917185</guid>
            <category><![CDATA[postmortem]]></category>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[software]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[outage]]></category>
            <dc:creator><![CDATA[Tyler Finethy]]></dc:creator>
            <pubDate>Sun, 16 Jan 2022 19:12:15 GMT</pubDate>
            <atom:updated>2022-01-17T00:51:10.675Z</atom:updated>
            <content:encoded><![CDATA[<h4>What we need to take away from the incident as engineers</h4><figure><img alt="Picture of the facebook logo being erased" src="https://cdn-images-1.medium.com/max/1024/0*mDx-Y5afy_VlzfVs" /><figcaption>Image courtesy of <a href="https://www.pexels.com/photo/silver-iphone-2228555/">pixels.com</a></figcaption></figure><p>As many of us remember, on October 4th, 2021, Facebook, Instagram, WhatsApp, and many other applications under the umbrella of, what is now, Meta disappeared from the internet. The sites were down for six to seven hours, and <a href="https://www.bloomberg.com/news/articles/2021-10-04/zuckerberg-loses-7-billion-in-hours-as-facebook-plunges">shares in the company plunged 5%</a> due to the mistake. This outage appeared as a worst-case scenario, code red, I’m-going-to-lose-my-job engineering failure.</p><p>While it’s always entertaining to poke fun, it’s important to remember that this is a multi-billion dollar organization with thousands of engineers, more than <a href="https://datacenterfrontier.com/meta-adds-more-data-centers-in-iowa-pushing-campus-to-5-million-sf/">47 global data centers</a>, and over twenty years of experience operating these systems. If an engineer there could press enter and watch every alert in the company go off, should we expect to fair better? Postmortems should be looked at like open-source software; by making them free and accessible, we can all build better software by learning from others’ mistakes.</p><h3>The Start</h3><p>After folks started noticing, <a href="https://engineering.fb.com/2021/10/04/networking-traffic/outage/">Facebook wrote a post</a> apologizing for the inconvenience. They also explained that a change to their <strong>backbone routers </strong>that coordinate traffic between data centers caused the problem. Backbone routers connect <strong>autonomous systems (ASs)</strong> in large inter-networks.</p><blockquote>Check out <a href="https://www.cloudflare.com/learning/">CloudFlare’s learning center</a> for an overview about ASs, DNS, and/or BGP as a proper explanation of each deserves an entire article.</blockquote><p>This configuration change resulted in cascading failures that caused <strong>Domain Name Service (DNS) </strong>providers like <a href="https://blog.cloudflare.com/october-2021-facebook-outage/">CloudFlare to think they had a problem</a> as their path to Facebook vanished. After an investigation, CloudFlare and others confirmed that for whatever reason, Facebook unregistered itself from the in. This “unregistering” happened through <strong>Border Gateway Protocol (BGP)</strong> updates.</p><h3>Mystery Solved?</h3><p>The next day, Facebook put out <a href="https://engineering.fb.com/2021/10/05/networking-traffic/outage-details/">another message</a> with a full report. Their DNS servers disable BGP routes for locations that are deemed unhealthy. This policy makes a lot of sense, especially with at least 47 fail-over locations.</p><figure><img alt="Graph showing two spikes when Facebook sent out BGP updates removing the site from the internet" src="https://cdn-images-1.medium.com/max/1024/0*vJJpDA-hGM1_9sIY.png" /><figcaption>Image courtesy of <a href="https://blog.cloudflare.com/content/images/2021/10/image4-11.png">CloudFlare</a> showing the BGP withdrawn announcements from Facebook</figcaption></figure><p>The problem here goes back to the backbone router change. Since the entire backbone removed, the data centers registered themselves as unhealthy, and thus the BGP routes were withdrawn. While they had an audit tool to prevent mistakes to the router, the change made it through due to a bug discovered after the outage.</p><blockquote>Our systems are designed to audit commands like these to prevent mistakes like this, but a bug in that audit tool prevented it from properly stopping the command —Meta</blockquote><p>During the outage, engineers were unable to access the data centers through normal means because the authentication was tied to the unavailable servers, and the outage prevented standard operating procedure as services like messenger were unavailable. Eventually however, onsite engineers were able to get into the facilities and restore the backbone connectivity.</p><p>There’s a lot to unpack here, like did they need a blow torch to break into their own data centers? Also at least from my perspective, this story feels too abstract. I want to simulate these networks and see if we can recreate both what was happening at Facebook and observed by the rest of the internet.</p><h3>The Laboratory</h3><p>To try and recreate what happened, I’m using a tool called <a href="https://ipmininet.readthedocs.io/en/latest/"><strong>IPMininet</strong></a>.</p><p>As an aside, while I’ve used <a href="http://mininet.org/"><strong>Mininet</strong></a> before in a graduate networking course, I was surprised I couldn’t find a more modern or user-friendly solution to simulate networks.</p><p>Anyways! Let’s start with a simplified example using DNS to explore how these technologies interact. When things are working, a client queries Cloudflare for the Facebook DNS records to make the subsequent requests.</p><figure><img alt="Flow graph showing DNS and HTTP queries" src="https://cdn-images-1.medium.com/max/354/1*Db6npavzBQamGOGp-QWHvA.png" /><figcaption>Clients first need to make DNS requests to determine how to access Facebook.</figcaption></figure><p>IPMininet lets users describe topologies like this using the Python programming language. For example, I’ve used this API to simulate the situation described:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3dae82e8a458266f7c126602673dadc0/href">https://medium.com/media/3dae82e8a458266f7c126602673dadc0/href</a></iframe><p>With this topology, we can query the DNS server and ping the API server:</p><pre>mininet&gt; client dig <a href="http://twitter.com/cloudflare">@cloudflare</a> api.facebook.com +short<br>192.168.0.2<br>mininet&gt; client ping 192.168.0.2<br>PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.<br>64 bytes from 192.168.0.2: icmp_seq=1 ttl=62 time=0.062 ms<br>...</pre><p>These records have a time-to-live (TLS) of 60s, so our service should re-query the server every minute. An actual DNS query will be much more complex, traveling through the root server and traversing the DNS hierarchy until the <a href="https://www.cloudflare.com/learning/dns/dns-server-types/#authoritative-nameserver"><strong>authoritative nameserver</strong></a> is found. Running dig locally against facebook.com gives a real facebook IP:</p><pre>&gt; dig @1.1.1.1 facebook.com +short<br>157.240.241.35</pre><p>This example gives us something to experiment with, but a lot of us are already familiar with DNS. Setting up a network that includes multiple ASs, communicates via eBGP, and performs the DNS traversal gets us a lot closer to reality:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/717/1*wnQ4kO1AuoWiUdqR7UTYdg.png" /><figcaption>A client in some AS makes the DNS query to Cloudflare, which forwards to query to Facebook’s DNS servers available via eBGP.</figcaption></figure><p>I tried using IPMininet again for this task and found it incredibly difficult. So, starting as simple as possible, I tried setting up two ASs that communicate via eBGP:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5ddfebd7b2a02c55c33416c7c8bd6a51/href">https://medium.com/media/5ddfebd7b2a02c55c33416c7c8bd6a51/href</a></iframe><p>Unfortunately, when I went to confirm the eBGP connection I ran into a number of errors that prevented me from doing so:</p><pre>mininet&gt; pingall<br>*** Ping: testing reachability over IPv4 and IPv6<br>has1r1 --IPv4--&gt; X <br>has1r1 --IPv6--&gt; X <br>has2r1 --IPv4--&gt; X <br>has2r1 --IPv6--&gt; X <br>*** Results: 100% dropped (0/4 received)<br>mininet&gt; noecho as2r1<br>*** Enter a command for node: as2r1 &lt;cmd&gt;mininet&gt;telnet localhost bgpd<br>*** Unknown command: telnet localhost bgpd</pre><p>It doesn’t appear to be a topology issue, as the advanced BGP example complains about the same problems. I think it‘s a missing utility or package, so I restarted from scratch to no avail. Nonetheless, I’ll continue to play with it and make a follow-up with a complete recreation if I figure it out.</p><h3>Lessons Learned</h3><p>The second report from Meta lists several follow-up action items, including increasing their testing, drills, and overall resilience. Having the capacity to run outage drills, find the weak points in the chain, and come up with action plans can make huge differences. Netflix has gone to the extreme, implementing a <a href="https://netflixtechblog.com/the-netflix-simian-army-16e57fbab116">chaos monkey tool</a> that automatically takes down part of the infrastructure to understand where failures can occur.</p><p>A lesson for the rest of us to think about is how inaccessible some of these technologies are. While few of us will work with BGP daily, experimenting with software is critical in identifying points of failure and making informed decisions. Julia Evans wrote a great post titled <a href="https://jvns.ca/blog/2021/10/05/tools-to-look-at-bgp-routes/">Tools to explore BGP</a>, where she mentions that it’s impossible to publish routes or broadcast updates without running an ASN yourself.</p><blockquote>But with BGP, I think that unless you own your own ASN, you can’t publish routes yourself — Julia Evans</blockquote><h3>References</h3><ol><li><a href="https://www.bloomberg.com/news/articles/2021-10-04/zuckerberg-loses-7-billion-in-hours-as-facebook-plunges">https://www.bloomberg.com/news/articles/2021-10-04/zuckerberg-loses-7-billion-in-hours-as-facebook-plunges</a></li><li><a href="https://datacenterfrontier.com/meta-adds-more-data-centers-in-iowa-pushing-campus-to-5-million-sf/">https://datacenterfrontier.com/meta-adds-more-data-centers-in-iowa-pushing-campus-to-5-million-sf/</a></li><li><a href="https://engineering.fb.com/2021/10/04/networking-traffic/outage/">https://engineering.fb.com/2021/10/04/networking-traffic/outage/</a></li><li><a href="https://blog.cloudflare.com/october-2021-facebook-outage/">https://blog.cloudflare.com/october-2021-facebook-outage/</a></li><li><a href="https://engineering.fb.com/2021/10/05/networking-traffic/outage-details/">https://engineering.fb.com/2021/10/05/networking-traffic/outage-details/</a></li><li><a href="https://www.cloudflare.com/learning/">https://www.cloudflare.com/learning/</a></li><li><a href="https://ipmininet.readthedocs.io/en/latest/">https://ipmininet.readthedocs.io/en/latest/</a></li><li><a href="http://mininet.org/">http://mininet.org/</a></li><li><a href="https://www.cloudflare.com/learning/dns/dns-server-types/#authoritative-nameserver">https://www.cloudflare.com/learning/dns/dns-server-types/#authoritative-nameserver</a></li><li><a href="https://netflixtechblog.com/the-netflix-simian-army-16e57fbab116">https://netflixtechblog.com/the-netflix-simian-army-16e57fbab116</a></li><li><a href="https://jvns.ca/blog/2021/10/05/tools-to-look-at-bgp-routes/">https://jvns.ca/blog/2021/10/05/tools-to-look-at-bgp-routes/</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1e742f917185" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Cloud Isn’t Developer-Friendly Anymore]]></title>
            <link>https://medium.com/better-programming/the-cloud-isnt-developer-friendly-anymore-9f57ad55d6be?source=rss-e95ef4be7a2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/9f57ad55d6be</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[cloud]]></category>
            <category><![CDATA[big-data]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[data-science]]></category>
            <dc:creator><![CDATA[Tyler Finethy]]></dc:creator>
            <pubDate>Thu, 11 Mar 2021 18:25:15 GMT</pubDate>
            <atom:updated>2021-03-11T18:25:15.644Z</atom:updated>
            <content:encoded><![CDATA[<h4>And it’s a primary reason for production outages</h4><figure><img alt="Notes stuck to computer monitor" src="https://cdn-images-1.medium.com/max/1024/0*zDHWranjiAFe3Qzx" /><figcaption>Photo by <a href="https://unsplash.com/@sigmund?utm_source=medium&amp;utm_medium=referral">Sigmund</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a>.</figcaption></figure><p>When I mention configuration management, I know the battle-worn developers out there shiver. I can’t count the number of failed releases I’ve seen as a result of a seemingly innocuous config change. Even Google has published seven postmortem reports related to config errors. <a href="https://github.com/danluu/post-mortems#config-errors">During one incident</a>, they deny-listed / prompting every URL to show a warning.</p><p>Now, with modern deployment strategies, our releases should fail well before they reach production. So why on earth do these issues persist? The harsh truth is lazy instantiation is lazy, and it’s time for us to address the problems for all sides.</p><h3>Let’s Start Simple</h3><p>So, what the heck is lazy instantiation and what does that have to do with production outages caused by configuration changes? The easiest way to explain this is through an example.</p><p>Here’s a snippet of code written in Go where an application is using an external MySQL database:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dc85fe6fa332611150a4ded328f35783/href">https://medium.com/media/dc85fe6fa332611150a4ded328f35783/href</a></iframe><p>If the variable connStr is incorrect, will this code panic?</p><p>The answer in this case is actually no. While it looks like the code opens a connection to the database, it actually lazily instantiates a database pool object and waits until the first request.</p><p>This can differ based on the database driver. The <a href="https://golang.org/pkg/database/sql/#Open">sql.Open documentation</a> recommends actually confirming that the source is valid:</p><blockquote>“To verify that the data source name is valid, call Ping.”</blockquote><p>Let’s say you have an API server that passes this database object to the request handlers. In that case, the server will boot and appear healthy while every incoming request subsequently fails.</p><p>In simple terms, lazy instantiation is the process of waiting for the first thing to do before eagerly doing work (in this case, opening a connection to the database). This creates a big problem: There’s no way of knowing if our service is broken until it fails. The lesson here is<strong> </strong>services should verify configuration options on boot. Otherwise, we risk precluding error detection due to sheer laziness or ignorance.</p><p>What happens when it’s measurably harder than just running Ping to confirm? Let’s take a look at verifying S3 bucket policies, where this problem rears its ugly head.</p><h3>Bucket Policies</h3><p>If you don’t know, S3 is <a href="https://aws.amazon.com/s3/">an object storage service</a> by Amazon that makes the problem of cloud file storage ridiculously easy. The kicker here is that it requires a fair bit of setup and configuration in order to be utilized correctly.</p><p>In general, when interacting with S3, we have some credential that can have various permissions like ListBucket, GetObject, PutObject, or DeleteObject.</p><p>Say our application relies on a credential that needs to get, put, and delete objects. How can we ensure this some given credential is correct at boot time?</p><figure><img alt="Example picture of our application communicating with S3" src="https://cdn-images-1.medium.com/max/618/1*CXSlMUSjZ2iQMgecclDRWA.png" /><figcaption>The application needs permissions to perform different actions on an S3 bucket across the internet. Diagram designed using <a href="https://app.diagrams.net/">app.diagrams.net</a>.</figcaption></figure><p>If you guessed that we need to try getting, putting, and deleting an object, you’re right! Unfortunately, S3 doesn’t support any actions to test a credential. Here’s an example of what the validation has to look like in this case:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6626cfc1d0a284f412056b27203bfee2/href">https://medium.com/media/6626cfc1d0a284f412056b27203bfee2/href</a></iframe><p>The takeaway here should really be this: When writing developer software, we should try to support the full needs of our users. Yes, a working API with “11 9s” of durability is great, but how does it fit into the whole picture when you consider things like continuous integration and delivery?</p><p>You might think that this is just an Amazon problem or a problem with SaaS or PaaS providers, but let’s look at one last example that should change your mind.</p><h3>What Proxy? Where?</h3><p>I just faced this problem recently. Say your application supports an <a href="https://en.wikipedia.org/wiki/Proxy_server">outbound HTTP(S) proxy</a>. This means you have your application that sends outgoing HTTP requests to the proxy, which then communicates to the internet. How can you ensure the proxy is configured correctly <em>without </em>making a request to the internet?</p><figure><img alt="Example topology of an application that sends all HTTP(S) traffic through a proxy" src="https://cdn-images-1.medium.com/max/904/1*qJpJkgQectdYtP-ujiNQOw.png" /><figcaption>Example topology of an application that sends all HTTP(S) traffic through a proxy. Diagram designed using <a href="https://app.diagrams.net/">app.diagrams.net</a>.</figcaption></figure><p>Maybe we can make a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD">HEAD request</a> to the proxy with the correct headers, and if we get a <a href="https://httpstatuses.com/">200 OK</a> back, everything is all good?</p><p>Without knowing more about the specific proxy or the implementation, that might not work. We might have the bad credentials and get a 200 OK anyways! We can confirm this by using <a href="https://hackage.haskell.org/package/hprox">hprox</a>:</p><pre>&gt; hprox -p 1122 -a userpass.txt &amp;<br>&gt; curl -I localhost:1122<br>HTTP/1.1 200 OK<br>Date: Thu, 04 Mar 2021 21:03:10 GMT<br>Server: Apache<br>Vary: Accept-Encoding<br>Content-Type: text/html</pre><p>So that’s not going to work. In lieu of some existing standard, we’ll have to make do on our own. <a href="https://tools.ietf.org/html/rfc7231#section-4.3.6">RFC 7231 section 4.3.6</a> talks about the CONNECT method and even mentions the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authorization">Proxy-Authorization</a> header. When we do that:</p><pre>&gt; hprox -p 1122 -a userpass.txt &amp;<br>&gt; curl -X CONNECT -v localhost:1122<br>...<br>&lt; HTTP/1.1 407 Proxy Authentication Required<br>&lt; Transfer-Encoding: chunked<br>&lt; Date: Thu, 04 Mar 2021 21:06:37 GMT<br>&lt; Server: Apache<br>&lt; Vary: Accept-Encoding<br>&lt; Proxy-Authenticate: Basic realm=&quot;hprox&quot;<br>...</pre><p>This gives us the correct response until we provide the right credentials. Now using this, we can craft some validation code to use at boot time to ensure that any bad configurations don’t make it up to production:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9ed0a918a529b5569e8e280149dca4c8/href">https://medium.com/media/9ed0a918a529b5569e8e280149dca4c8/href</a></iframe><p>It’s time to make an effort to support configuration validation from the get-go. I think the easiest way to do this is through more thorough contract testing.</p><blockquote>“Contract tests assert that inter-application messages conform to a shared understanding that is documented in a contract.” — <a href="https://docs.pact.io/">Pact docs</a></blockquote><p>One of the simplest contract tests is Connect or Ping, so by implementing more contract testing across our applications, we’d solve the problem implicitly.</p><h3>Conclusion</h3><p>Until the world changes and every service exposes an API intended to help applications validate configuration options and ensure runtime usability, we’ll have to come up with tricks to ensure everything is correct. If we want to reduce the number of times our apps crash after deploying, we’ll need to:</p><ul><li>Have applications that verify every configuration option on boot.</li><li>Write developer software that supports the full CI/CD methodology.</li><li>Introduce contract testing as a standard practice to identify holes in our services.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9f57ad55d6be" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/the-cloud-isnt-developer-friendly-anymore-9f57ad55d6be">The Cloud Isn’t Developer-Friendly Anymore</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Debug Go Like a Pro]]></title>
            <link>https://medium.com/better-programming/debug-go-like-a-pro-213d4d74e940?source=rss-e95ef4be7a2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/213d4d74e940</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[debugging]]></category>
            <category><![CDATA[golang]]></category>
            <dc:creator><![CDATA[Tyler Finethy]]></dc:creator>
            <pubDate>Thu, 06 Feb 2020 21:23:36 GMT</pubDate>
            <atom:updated>2020-02-06T21:23:36.251Z</atom:updated>
            <content:encoded><![CDATA[<h4>From profiling to debugging and everything in between</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Njhaxg33Sg6mwTyEB-XUiQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@zanilic?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Zan</a> on <a href="https://unsplash.com/s/photos/debug?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Once you understand the basics, Golang can make you more productive than ever before. But what do you do when things go wrong?</p><p>You may not know this, but Go natively includes <a href="https://golang.org/pkg/runtime/pprof/">pprof</a> for recording and visualizing run-time profiling data. Third-party tools like <a href="https://github.com/go-delve/delve">delve</a> add support for line-by-line debugging. Leak and race detectors can defend against non-deterministic behavior.</p><p>If you haven’t seen or used these tools before, they will quickly become powerful additions to your arsenal of Golang tools.</p><h3>Why Don’t I Just Print Everything?</h3><p>I’ve met a lot of developers who rarely open the debugger when they run into an issue with their code. I don’t think that’s wrong. If you’re writing unit tests, linting your code, and refactoring along the way, then the quick-and-dirty approach can work for a majority of cases.</p><p>Conversely, I’ve been in the throes of troubleshooting problems and realized it’s quicker to pepper in some breakpoints and open an interactive debugger than continually add assertions and print statements.</p><figure><img alt="Graph of a memory leak slowly building up, then the fix leveling out." src="https://cdn-images-1.medium.com/max/1024/0*5vvk22KdDquCQrga.png" /><figcaption>Example of a graph showing a memory leak being fixed by <a href="https://medium.com/@KentGruber/tracking-down-a-golang-memory-leak-with-grmon-74569a00a177">Kent Gruber</a></figcaption></figure><p>For example, one day I was looking at the memory graph for a web application I helped maintain. Every day the total memory usage slowly increased to the point that the server needed to be restarted to remain stable. This is a classic example of a memory leak.</p><p>The quick-and-dirty approach suggests that we read through the code ensuring spawned <a href="https://gobyexample.com/goroutines">goroutines</a> exit, allocated variables get garbage collected, connections properly close, etc. Instead, we profiled the application and found the memory leak in a matter of minutes. An elusive, single statement caused it — usually the case for this class of error.</p><p>This overview will introduce you to some of the tools I use almost every day to solve problems like this one.</p><h3>Profiling Recording and Visualization</h3><p>To get started, let&#39;s take a basic Golang web server with a graceful shutdown and send some artificial traffic. Then we’ll use the pprof tool to gather as much information as possible.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c4c2b6e35de405559780446e3c7a0821/href">https://medium.com/media/c4c2b6e35de405559780446e3c7a0821/href</a></iframe><p>We can ensure this works by doing:</p><pre>$ go run main.go &amp;<br>$ curl localhost:8080<br>Hello World!</pre><p>Now we can profile the CPU by including this snippet:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8864b90a91dba0525b5d1d7efecc4b67/href">https://medium.com/media/8864b90a91dba0525b5d1d7efecc4b67/href</a></iframe><p>We’ll use a load testing tool to exercise the web server thoroughly to simulate normal to heavy traffic. I used the testing tool <a href="https://github.com/tsenart/vegeta">vegeta</a> to accomplish this:</p><pre>$ echo &quot;GET http://localhost:8080&quot; | vegeta attack -duration=5s<br>Hello world!<br>...</pre><p>When we shut down the go web server, we’ll see a file, cpu.prof, that contains the CPU profile. This profile can then be visualized with the pprof tool:</p><pre>$ go tool pprof cpu.prof<br>Type: cpu<br>Time: Jan 16, 2020 at 4:51pm (EST)<br>Duration: 9.43s, Total samples = 50ms ( 0.53%)<br>Entering interactive mode (type &quot;help&quot; for commands, &quot;o&quot; for options)<br>(pprof) top 10<br>Showing nodes accounting for 50ms, 100% of 50ms total<br>Showing top 10 nodes out of 24<br>      flat  flat%   sum%        cum   cum%<br>      20ms 40.00% 40.00%       20ms 40.00%  syscall.syscall<br>...<br></pre><p>This is good a good start, but Go can do better. We want to profile our application as it receives traffic, that way we don’t have to rely on simulated traffic or add additional code to write profiles to file. Adding the net/http/pprof import will automatically add additional handlers to our web server:</p><pre>import _ &quot;net/http/pprof&quot;</pre><p>With that added, we can hit the /debug/pprof/ route through our web browser and see the pprof page teeming with information.</p><figure><img alt="Example of the Golang profiler pprof’s web interface" src="https://cdn-images-1.medium.com/max/1024/1*E_3_jOh9b1pMvKAue07asQ.png" /><figcaption>Example of what you’ll see when navigating to the /debug/pprof/ route</figcaption></figure><p>We can get the same information as before by running the command:</p><pre>$ go tool pprof -top http://localhost:8080/debug/pprof/heap</pre><p>You can also:</p><ul><li>Generate images based off of the type of profile.</li><li>Create <a href="http://www.brendangregg.com/flamegraphs.html">Flame Graphs</a> to visualize the time spent by the application.</li><li>Track Goroutines to detect leaks before they cause degraded service.</li></ul><p>Note that for production web servers, we rarely want to avoid exposing this information to the world and should instead bind them to a different internal port.</p><h3>Delve the Interactive Debugger</h3><p>Delve is advertised as:</p><blockquote>… a simple, full featured debugging tool for Go. Delve should be easy to invoke and easy to use. Chances are if you’re using a debugger, things aren’t going your way. With that in mind, Delve should stay out of your way as much as possible.</blockquote><p>To that end, it works really well when you have an issue that’s taking just a little too long to figure out.</p><p>Getting started with the tool is fairly easy, just follow the <a href="https://github.com/go-delve/delve/tree/master/Documentation/installation">installation steps</a>. Add a runtime.Breakpoint() statement and run your code using dlv:</p><pre>$ dlv debug main.go<br>Type &#39;help&#39; for list of commands.<br>(dlv) continue</pre><p>Once you hit the breakpoint you’ll see the block of code, for example in the webserver above I put the it in the handler:</p><pre>&gt; main.handler() ./main.go:20 (PC: 0x1495476)<br>    15:         _ &quot;net/http/pprof&quot;<br>    16: )<br>    17:<br>    18: func handler(w http.ResponseWriter, r *http.Request) {<br>    19:         runtime.Breakpoint()<br>=&gt;  20:         fmt.Fprintf(w, &quot;Hello World!\n&quot;)<br>    21: }<br>    22:<br>    23: func main() {<br>    24:         srv := http.Server{<br>    25:                 Addr:         &quot;:8080&quot;,<br>(dlv)</pre><p>Now you can go line by line using the next or n command or dig deeper into a function using the step or s command.</p><figure><img alt="Screenshot of interacting with VS Code test and debug buttons" src="https://cdn-images-1.medium.com/max/1024/1*CfR1iPgKhmdYMjQO7melDQ.png" /><figcaption>Example of VS Code with the Golang extension showing the debug test button</figcaption></figure><p>If you’re a fan of a nice UI and clicking buttons instead of using your keyboard, <a href="https://code.visualstudio.com/">VS Code</a> has great delve support. When writing unit tests using the native testing library, you’ll see a button to debug test which will initialize delve and let you step through the code via VS Code in an interactive session.</p><p>For more information on debugging Go code using VS Code check out the <a href="https://github.com/Microsoft/vscode-go/wiki/Debugging-Go-code-using-VS-Code">Microsoft wiki</a> on it.</p><p>Delve can make adding breakpoints, testing assertions, and diving deep into packages a breeze. Don’t be afraid to use it the next time you get stuck on a problem and want to know more about what’s happening.</p><h3>Leak and Race Detectors</h3><p>The last topic I’m going to cover is how to add Golang leak and race detectors to your tests. If you haven’t encountered a race condition or experienced a Goroutine memory leak, consider yourself lucky.</p><p>In 2017 Uber open-sourced the <a href="http://github.com/uber-go/goleak">goleak</a> package, which is a simple tool to check that marks the given TestingT as failed if any extra goroutines are found by Find.</p><p>It looks like this:</p><pre>func TestA(t *testing.T) {<br>   defer goleak.VerifyNone(t)<br>   // test logic here.<br>}</pre><p>While you’re doing complex asynchronous work, you can ensure that you both avoid regressions and follow the fifth tenet of <a href="https://the-zen-of-go.netlify.com/"><em>The Zen of Go</em></a>:</p><blockquote>Before you launch a goroutine, know when it will stop.</blockquote><p>Finally, after ensuring you have no Goleaks, you’ll want to protect against race conditions. Thankfully the <a href="https://golang.org/doc/articles/race_detector.html">data race detector</a> is built-in. Consider the example from the race detector’s documentation:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/20905fac6606642d253b2a5f2f63cc81/href">https://medium.com/media/20905fac6606642d253b2a5f2f63cc81/href</a></iframe><p>This is a data race that can lead to crashes and memory corruption. Running this snippet with the -race flag leads to a panic with a helpful error message:</p><pre>go run -race main.go <br>==================<br>WARNING: DATA RACE<br>Write at 0x00c0000e2210 by goroutine 8:<br>  runtime.mapassign_faststr()<br>      /usr/local/Cellar/go/1.13.6/libexec/src/runtime/map_faststr.go:202 +0x0<br>  main.main.func1()<br>      /PATH/main.go:19 +0x5d</pre><pre>Previous write at 0x00c0000e2210 by main goroutine:<br>  runtime.mapassign_faststr()<br>      /usr/local/Cellar/go/1.13.6/libexec/src/runtime/map_faststr.go:202 +0x0<br>  main.main()<br>      /PATH/main.go:22 +0xc6</pre><pre>Goroutine 8 (running) created at:<br>  main.main()<br>      /PATH/main.go:18 +0x97<br>==================<br>2 b<br>1 a<br>Found 1 data race(s)</pre><p>While you can use the flag during execution of your code, it’s most helpful to add to your go test command to detect races as you write tests.</p><h3>Conclusion</h3><p>These are just some of the great tools available in the Golang ecosystem to aid in observing, debugging, and preventing production failures in your codebases. If you’re looking to go further I recommend taking a look at:</p><ul><li>Distributed tracing like <a href="https://opentracing.io/">Open-tracing Go</a>.</li><li>Time-series monitoring using a tool like <a href="https://prometheus.io/">Prometheu</a>s.</li><li>Structured logging using <a href="https://github.com/sirupsen/logrus">logrus</a>.</li></ul><p>For more information on any of the tools listed above check out the resources section for full documentation and manuals.</p><h3>Resources</h3><ul><li><a href="https://golang.org/pkg/runtime/pprof/">Runtime pprof</a> and <a href="https://golang.org/pkg/net/http/pprof/">net pprof</a></li><li><a href="https://github.com/go-delve/delve">Go delve</a></li><li><a href="https://medium.com/@KentGruber/tracking-down-a-golang-memory-leak-with-grmon-74569a00a177">Tracking down a Golang Leak</a></li><li><a href="https://gobyexample.com/goroutines">Goroutines</a></li><li><a href="https://github.com/tsenart/vegeta">Vegeta load testing tool</a></li><li><a href="http://www.brendangregg.com/flamegraphs.html">Flame Graphs</a></li><li><a href="https://github.com/go-delve/delve/tree/master/Documentation/installation">Delve installation steps</a></li><li><a href="https://code.visualstudio.com/">VS Code</a></li><li><a href="https://github.com/Microsoft/vscode-go/wiki/Debugging-Go-code-using-VS-Code">Debugging Go Code using VS Code by Microsoft</a></li><li><a href="http://github.com/uber-go/goleak">Goleak</a></li><li><a href="https://the-zen-of-go.netlify.com/">The Zen of Go</a></li><li><a href="https://golang.org/doc/articles/race_detector.html">The Go Race Detector</a></li><li><a href="https://opentracing.io/">Open Tracing</a></li><li><a href="https://prometheus.io/">Prometheus</a></li><li><a href="https://github.com/sirupsen/logrus">Logrus</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=213d4d74e940" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/debug-go-like-a-pro-213d4d74e940">Debug Go Like a Pro</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Windows Containers on Kubernetes]]></title>
            <link>https://medium.com/better-programming/windows-containers-on-kubernetes-643c2356622a?source=rss-e95ef4be7a2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/643c2356622a</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[windows]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Tyler Finethy]]></dc:creator>
            <pubDate>Mon, 06 Jan 2020 13:20:30 GMT</pubDate>
            <atom:updated>2020-01-07T22:01:03.699Z</atom:updated>
            <content:encoded><![CDATA[<h4>Is the technology ready for prime time?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GVB6YPIbNNEQclEUWfs7Cg.png" /><figcaption>Open for preview — Windows Server container on an Azure Kubernetes Service (AKS) cluster. How does it match up to longstanding Linux-based container alternative?</figcaption></figure><p>While still in preview, <a href="https://azure.microsoft.com/en-us/services/kubernetes-service/">Azure Kubernetes Service</a> (AKS) <a href="https://azure.microsoft.com/en-us/blog/announcing-the-preview-of-windows-server-containers-support-in-azure-kubernetes-service/">recently announced</a>¹ support for Windows Server containers.</p><p>You can deploy ASP.NET applications, run <a href="https://docs.microsoft.com/en-us/powershell/scripting/overview">PowerShell</a> or Linux subsystem scripts, and enable autoscaling to meet customer demand. I’ve been using the service for about a month now, these are my key takeaways.</p><h3>Windows Containers Are Slower and Clunky</h3><p>Container-based development has a number of benefits like consistent environments, isolation, and a run-anywhere mentality².</p><p>When using Linux-based containers on Kubernetes, it usually comes with the advantage of being lightweight enough to scale and quickly meet traffic needs. Even the <em>About Windows Containers</em> page speaks to these benefits:</p><blockquote>“Containers provide a lightweight, isolated environment that makes apps easier to develop, deploy, and manage. Containers start and stop quickly, making them ideal for apps that need to rapidly adapt to changing demand.”³</blockquote><p>Coming from the Linux-based container world, I was surprised at both the larger size of the images and the amount of time it takes to scale new Kubernetes nodes and deploy more pods.</p><p>The default ltsc2019 image is over 850 megabytes, so I don’t know if we’re ready to use the lightweight phrase just yet but everything else still rings true.</p><p>Windows containers also require more resources than their counterpart making the cost higher, at least two times as much if you’re comparing Standard_DS2_v2 to the Standard_DS3_v2 on Azure⁴ (the required minimum size for Windows node pools).</p><p>I’ve only used the Standard_DS3_v2 nodes when using Windows containers, so take this with a grain of salt, but I’ve noticed a high amount of latency and slowdown when interacting with running pods.</p><p>For example, when debugging systems, I often run a command like:</p><pre>$ kubectl exec -it [pod-name] /bin/bash</pre><p>On Windows this becomes:</p><pre>$ kubectl exec -it [pod-name] powershell.exe<br>Windows PowerShell                                                                                                                                                                                      <br>Copyright (C) Microsoft Corporation. All rights reserved.                                                                                                                                               <br>                                                                                                                                                                                                        <br>PS C:\&gt;</pre><p>Running commands from here like downloading files or installing executables can take some time, although it’s pretty awesome to hop into a Windows container on my Mac. It’s definitely a huge step forward for developers like me who usually run from any Windows development work.</p><p>Combine this functionality with the recent Windows Subsystem for Linux (WSL) and you have a shared tool-chain across operating systems.</p><p>I’m now using a previously tested bash script on Windows through Kubernetes with minimal effort. This support further lowers the barrier of entry for more developers interested in cross-platform support.</p><h3>Getting Everything Right Is an Art</h3><p>While there are both Windows Server Core and Nanoserver base images available for Windows containers, as far as I can tell, AKS only supports the Windows Server Core images. This is because:</p><blockquote>“Windows Server containers and the underlying host share a single kernel, the container’s base image OS version must match that of the host.”⁵</blockquote><p>If you don’t get this right, expect to see The operating system of the container does not match the operating system of the host.</p><p>I saw this a lot. I used Azure Pipelines⁶ to build the container image from a custom Dockerfile. I then needed to make my base image Windows version to match the Azure Pipeline VM version.</p><p>Next, I matched the container image to the Kubernetes node. I wasn’t able to find the exact Windows version through the Azure docs, and running kubectl get nodes -o wide you get something like:</p><pre>NAME            OS-IMAGE                         KERNEL-VERSION<br>linux-node      Ubuntu 16.04.6 LTS               4.15.0-1061-azure<br>windows-node    Windows Server 2019 Datacenter   10.0.17763.737</pre><p>Which translated to a Docker base image of mcr.microsoft.com/windows/servercore:ltsc2019 and Azure VM image vmImage: ‘windows-2019’.</p><p>Hopefully, it’ll eventually be easier to match and configure these options, and eventually run Nanoserver base images on AKS.</p><h3>AKS Is Not Ready for Production Traffic</h3><p>I’m currently using AKS to run production compute jobs that are asynchronous and don’t directly impact customers. I think this is a good, safe use-case right now.</p><p>The reason I don’t think it’s ready for production web-traffic or anything synchronous is that I’ve run into more than a few issues with the actual cluster. Here are a few:</p><ul><li>Nodes have become unexpectedly unavailable with containers stuck in the ContainerCreating state.</li><li>Deleted jobs did not clean up the associated pods (Kubernetes API breakage).</li><li>Unsetting the node autoscaling option is impossible through the UI which leads to some manual scaling complications.</li></ul><p>I expected that issues like the Kubernetes API breakage could be quickly resolved through the Azure support, but without paying extra I couldn’t escalate the issue directly.</p><p>I believe there is a path through GitHub to submit issues like this but it seems insane that during a preview they don’t allow for feedback and bugs.</p><h3>References</h3><ol><li><a href="https://azure.microsoft.com/en-us/blog/announcing-the-preview-of-windows-server-containers-support-in-azure-kubernetes-service/">Announcing the preview of Windows Server Containers support in Azure Kubernetes service.</a></li><li><a href="https://cloud.google.com/containers/">Google Cloud — Containers</a></li><li><a href="https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/">Windows Containers</a></li><li><a href="https://azureprice.net/">https://azureprice.net/</a></li><li><a href="https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility">Containers version compatibility</a></li><li><a href="https://azure.microsoft.com/en-us/services/devops/pipelines/">Azure — Pipelines</a></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=643c2356622a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/windows-containers-on-kubernetes-643c2356622a">Windows Containers on Kubernetes</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Working fully remote: the dream or a nightmare]]></title>
            <link>https://medium.com/swlh/working-full-remote-the-dream-or-a-nightmare-13f6064564d1?source=rss-e95ef4be7a2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/13f6064564d1</guid>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[business]]></category>
            <category><![CDATA[remote-working]]></category>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[entrepreneurship]]></category>
            <dc:creator><![CDATA[Tyler Finethy]]></dc:creator>
            <pubDate>Mon, 11 Nov 2019 11:55:55 GMT</pubDate>
            <atom:updated>2019-11-11T13:25:38.318Z</atom:updated>
            <content:encoded><![CDATA[<h4>Will working from home make you a happier, more engaged employee? Maybe.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fHNw0moKbup-snCzZ4Nfdg.png" /><figcaption>Working from home can be a double-edged sword, but I prefer it to the routine commute and sometimes distracting office life</figcaption></figure><p>When I tell people I’m fully remote they have one of two reactions: they imagine some nightmarish trapped-at-home scenario where human interaction is nonexistent, or they dream of a life unchained from “the morning routine”. After about six months as a fully-remote employee, the result is somewhere in the middle.</p><h3>How did I get here?</h3><p>Similar to most newly graduated folks, I had no idea what I wanted to do next. I thrashed between pathways forward, from graduate programs to interviews with Google and the like. I almost ended up in the United Kingdom at business school. I even considered staying at school working for my data science professor, after a scarring interview with a hotel reservation company sent me reeling.</p><p>After applying to some-50-odd companies, which I now realize is typical, I landed at a startup in Boston and had that “I have no idea what I’m doing” moment. It took me about six months to fully understand the job and become a functioning member of a team. The soft skills of working in an industry setting, like properly wording an email or hitting the <em>reply all </em>button, aren’t taught in academia and certainly took time to master.</p><p>After my first job, searching for my next engineering job was a completely different experience. This time, interviews felt more like a two-way street, and I had now learned what to look for and what to avoid. I ended up picking a company based on location, salary, and a better work-life balance. However, I was still lukewarm with office-culture: the dreaded productivity metrics, staying long hours to be a “real developer”, and wasting valuable time commuting to-and-from work.</p><p>Through the years I worked with a few remote employees and knew that being a remote employee on a colocated team is an uphill battle. The freedom to work wherever you want and lack of distractions sounded amazing. On the other hand, I worried about missing out on water-cooler chats, company culture, and putting a lot of my fate in the hands of others. When I was offered the opportunity to work at a fully-remote organization with a great mission, it sounded like the best of both worlds, so I took the plunge and have been remote ever since.</p><h3>A day in the life</h3><p>Before I talk about expectations and realities, here’s what a rough overview of what my daily work schedule looks like:</p><p><strong>7:30–9:00 am</strong></p><ul><li>Start my day with coffee, breakfast, daily reading, etc</li><li>Respond to any urgent emails or slack messages</li><li>Prepare for any morning meetings</li></ul><p><strong>9:00–11:00 am</strong></p><ul><li><strong>Do not disturb</strong> set for at least an hour of focus time</li><li>Respond to any code reviews, feedback, or design/planning documents</li><li>Merge any accepted code changes</li></ul><p><strong>11:00–2:00 pm</strong></p><ul><li>Respond to any email or communicate in slack</li><li>Work on issues that require collaboration</li><li>Eat lunch and do some sort of physical activity or errand to get out of the house</li></ul><p><strong>2:00–4:30 pm</strong></p><ul><li><strong>Do not disturb</strong> set for at least another hour</li><li>Attend any afternoon meetings, pair coding sessions, or collaborate with other members of my team</li></ul><p><strong>4:30–6:00 pm:</strong></p><ul><li>Finish or polish any outstanding work</li><li>Perform less thought-intensive (busy) work</li><li>Wind down responding to slack, email, etc.</li></ul><p>There’s a lot that I didn’t include in my daily work schedule just because they’re less frequent. This includes customer issues, releases, or <a href="https://landing.google.com/sre/sre-book/chapters/eliminating-toil/">related toil work</a>.</p><p>The first thing you’ll probably notice as strange is the <strong>Do not disturb </strong>blocks. I’m a big believer in focus time and <a href="https://www.calnewport.com/books/deep-work/">deep work</a>. I had a colleague that said,</p><blockquote>“Coding and [software engineering work] is what happens in the space between the meetings on our calendars”</blockquote><p>While this is the case for a lot of software engineers, it’s insane to think that we prioritize our job only when we can fit it in. This can also lead to bad behaviors like working late, long after your peak productivity hours have passed.</p><p>The other thing you might notice is that communication is clustered. This is for a few reasons including reducing the number of distractions, <a href="https://m.signalvnoise.com/is-group-chat-making-you-sweat/#.groximv54">group chat can negatively impact your workday</a>, and I’m on a distributed team across many time zones so communicating later in the day makes sense. This has also had the effect of making the entire team value the meetings we do have a lot more.</p><p>The final crucial ingredient to the day is the physical activity or errand to break up the day and get out of the house. This is vital when working from home. Unlike working in a colocated environment you won’t get your daily dose of human interaction from your co-workers if you need that sort of thing (hint: you probably do even if you don’t know it). Try to avoid cabin fever at all costs.</p><h3>Myths and Half-Truths</h3><p>I’ve read several blog posts about the liberation and freedom you get from being a remote employee. People have also written about the loneliness and struggles of creating a strong work-life balance. <a href="https://open.buffer.com/state-remote-work-2018">Loneliness rates as the number one struggle with working from home</a>. Before you take the plunge, you should understand what it’s actually like beyond the myths and hype.</p><h4>Fully autonomous</h4><p>If you’ve ever read <a href="https://www.calnewport.com/books/so-good/"><em>So Good They Can’t Ignore You</em></a> then you know that autonomy over your workday can be a major factor in career satisfaction. This especially rings true in creative work because banging your head against a problem or design decision causes more strife than speed.</p><blockquote>“[control] turns out to be one of the most important traits you can acquire with [experience]… something so powerful and essential to the quest for work you love” — Cal Newport</blockquote><p>One of the best outcomes from remote work is the freedom to take a walk, grab a snack, and generally plan when and how you’ll get work done. You reduce the anxiety associated with wanting your manager to see you toiling away. Like I mentioned before, it increases engagement in meetings, written documents, and anything else that involves collaborating with your peers — you have limited opportunities to build relationships when you don’t see everyone every day.</p><h4>Traveling becomes the norm</h4><p>It’s true that as a remote employee you can work from anywhere, depending on your companies timezone and country restrictions. This doesn’t mean your life is going to turn into a Jack Kerouac novel, living out of a van and following the road wherever it takes you. You still want to remain grounded and delineate a space for work.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cP7M8RV349dYWqBUxtWw4g.jpeg" /><figcaption>The Amazon Loft in NYC, a co-working space free if you’re an existing AWS customer</figcaption></figure><p>I’ve found that finding <em>a good place to work</em> is difficult. Coffeehouses can be hit-or-miss depending on the WiFi signal, noise levels, and the amount of time the staff will let you sit in the space. Shared co-working spaces can be expensive, dark and dreary, or be further than you’re willing to travel. I went to one in New York City that was charging $550/mo for a shared desk with no natural lighting and lots of noise.</p><p>On the other hand, I spent the summer working from a lake with my family and I travel to work from warmer climates whenever I can. The dream of moving to the woods and escaping the rat-race might sound enticing but you’re also setting yourself up to further reduce the number of day-to-day interactions with people. When work friends no longer fill your social circle, you need to find places where you can build a strong group of friends outside of work. The point here is that you need a balance between both worlds.</p><h4>No peer pressure</h4><p>Lastly, let’s tackle the “no peer pressure” myth. For the most part, you can decide your schedule, you don’t have a manager looking over your shoulder, and you can work from anywhere. You should’ve escaped the pressure of working crazy hours and produce quality work right? Not quite.</p><p>Remote work comes with unique hurdles and challenges. For one, if you are used to getting daily recognition for a job-well-done you’ll have to find that satisfaction elsewhere. When you run into issues you can no longer tap a colleague on the shoulder and ask for help. You’re an island and if you struggle with knowing when working through an issue has turned into spinning your wheels this will be tough.</p><p>Communication becomes a delicate balance between over-communicating so everyone is on the same page or under-communicating to avoid bothering and respect someone in a focus time block. The best solution I’ve seen is to communicate regularly, but expect asynchronous delayed responses. You don’t want radio silence at the risk of having the police show up to check if you’re still alive.</p><h3>Conclusion</h3><p>While I’m still relatively new to remote-only work, I’ve been at it for long enough to understand the reality versus the hype. It’s not going to be a fix-all if you’re unhappy doing the work you already do. At the same time, it’s going to provide you the flexibility to decide how and when to do the work that matters. To recap:</p><ul><li>Fully autonomous work can supercharge your productivity if you stick to a strict schedule and respect your focus time hours</li><li>Working-from-anywhere is great but finding the right places where you can be free of distractions and do your best work can be challenging</li><li>While you no longer have a manager looking over your shoulder, communication and reassurance that you’re doing the right thing can be hard for those of us that need it</li><li>Avoid radio silence and cabin fever for both your own and your coworker’s sanity</li></ul><p>With all that said, unless you’re already far along in your career I would stick to the classic office work life. Early on you might need intense mentoring and autonomy requires a high level of job proficiency.</p><h3>Resources</h3><ul><li><a href="https://landing.google.com/sre/sre-book/chapters/eliminating-toil/">https://landing.google.com/sre/sre-book/chapters/eliminating-toil/</a></li><li><a href="https://www.calnewport.com/books/deep-work/">https://www.calnewport.com/books/deep-work/</a></li><li><a href="https://m.signalvnoise.com/is-group-chat-making-you-sweat/#.groximv54">https://m.signalvnoise.com/is-group-chat-making-you-sweat/#.groximv54</a></li><li><a href="https://open.buffer.com/state-remote-work-2018/#benefits">https://open.buffer.com/state-remote-work-2018</a></li><li><a href="https://www.calnewport.com/books/so-good/">https://www.calnewport.com/books/so-good/</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=13f6064564d1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/working-full-remote-the-dream-or-a-nightmare-13f6064564d1">Working fully remote: the dream or a nightmare</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[On-premise Kubernetes Clusters]]></title>
            <link>https://medium.com/swlh/on-premise-kubernetes-clusters-b36660ca6914?source=rss-e95ef4be7a2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/b36660ca6914</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[infrastructure]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Tyler Finethy]]></dc:creator>
            <pubDate>Tue, 29 Oct 2019 13:04:06 GMT</pubDate>
            <atom:updated>2019-10-29T23:33:23.324Z</atom:updated>
            <content:encoded><![CDATA[<h4>What you need to know when deploying Kubernetes yourself</h4><figure><img alt="Picture of the Kubernetes logo in a data center" src="https://cdn-images-1.medium.com/max/1024/1*V14u4skSNsIbl7Ab98zbeQ.png" /><figcaption>Running Kubernetes on-premise give developers a cloud-native experience or set your organization up to be cloud-agnostic.</figcaption></figure><p>Whether you have your own on-premise data center, have decided to forego the various managed cloud solutions, or are developing software for a company that has — there’s a few things you should know when getting started with on-premise K8s.</p><p>If you’re already familiar with Kubernetes you know that the <a href="https://kubernetes.io/docs/concepts/overview/components/#master-components">control plane</a> consists of the kube-apiserver, kube-scheduler, kube-controller-manager and an etcd datastore. For managed cloud solutions like <a href="https://cloud.google.com/kubernetes-engine/">Google’s Kubernetes Engine (GKE)</a> or <a href="https://azure.microsoft.com/en-us/services/kubernetes-service/">Azure’s Kubernetes Service (AKS)</a> it also includes the cloud-controller-manager. This is the component that connects the cluster to the external cloud services to provide networking, storage, authentication, and other feature support.</p><p>To successfully deploy a bespoke Kubernetes cluster and achieve a cloud-like experience you’ll need to replicate all the same features you get with a managed solution. At a high-level this means you’ll probably want to:</p><ul><li>Automate the deployment process</li><li>Choose a networking solution</li><li>Choose a storage solution</li><li>Handle security and authentication</li></ul><p>Lets look at each of these challenges individually, and I’ll try to provide enough of an overview to aid you in get started.</p><h3>Automating the deployment process</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/570/0*LEAgyUNzvGOp5ejw.jpg" /><figcaption>Using a tool like ansible can make deploying Kubernetes clusters on-premise trivial.</figcaption></figure><p>When deciding to manage your own Kubernetes clusters you’ll want to setup a few proof-of-concept (PoC) clusters to learn how everything works, perform performance and conformance tests, and try out different configuration options.</p><p>After this phase, automating the deployment process is an important if not necessary step to ensure consistency across any clusters you build. For this you have a few options, but the most popular are:</p><ul><li><a href="https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/">kubeadm</a>: a low-level tool that helps you bootstrap a minimum viable Kubernetes cluster that conforms to best practices</li><li><a href="https://github.com/kubernetes-sigs/kubespray">kubespray</a>: an ansible playbook that helps deploy production ready<em> </em>clusters</li></ul><p>If you already use ansible, kubespray is a great option otherwise I recommend writing automation around kubeadm using your preferred playbook tool after using it a few times. This will also increase your confidence and knowledge in the tooling surrounding Kubernetes.</p><h3>Choosing a network solution</h3><p>When designing clusters, choosing the right container networking interface (CNI) plugin can be the hardest part. This is because choosing a CNI that will work well with an existing network topology can be tough. Do you need BGP peering capabilities? Do you want an overlay network using vxlan? How close to bare-metal performance are you trying to get?</p><p>There are a lot of articles that compare the various CNI provider solutions (calico, weave, flannel, kube-router, etc.) that are must-reads like the <a href="https://itnext.io/benchmark-results-of-kubernetes-network-plugins-cni-over-10gbit-s-network-updated-april-2019-4a9886efe9c4"><em>benchmark results of Kubernetes network plugins</em></a><em> </em>article. I usually recommend Project Calico for its maturity, continued support, and large feature set or flannel for it’s simplicity.</p><p>For ingress traffic you’ll need to pick a load-balancer solution. For a simple configuration you can use MetalLB, but if you’re lucky enough to have F5 hardware load-balancers available I recommend checking out the <a href="https://clouddocs.f5.com/containers/v2/kubernetes/">K8s F5 BIG-IP Controller</a>. The controller supports connecting your network plugin to the F5 either through either vxlan or BGP peering. This gives the controller full visibility into pod health and provides the best performance.</p><h3>Choosing a storage solution</h3><p>Kubernetes provides a number of <a href="https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner">included storage volume plugins</a>. If you’re going on-premise you’ll probably want to use a network-attached storage (NAS) option to avoid forcing pods to be pinned to specific nodes.</p><p>For a cloud-like experience, you’ll need to add a plugin to dynamically create persistent volume objects that match the user’s persistent volume claims. You can use dynamic provisioning to reclaim these volume objects after a resource has been deleted.</p><p>Pure Storage has a great example helm chart, the <a href="https://github.com/purestorage/helm-charts"><em>Pure Service Orchestrator </em>(PSO)</a>, that provides smart provisioning although it only works for Pure Storage products.</p><h3>Handle security and authentication</h3><p>As anyone familiar with security knows, this is a rabbit-hole. You can always make your infrastructure more secure, and should be investing in continual improvements.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*mmukI0LzUK0ez4Xd.png" /><figcaption>Including different Kubernetes plugins can help build a secure, cloud-like experience for your users</figcaption></figure><p>When designing on-premise clusters you’ll have to decide where to draw the line. To really harden your cluster’s security you can add plugins like:</p><ul><li><a href="https://istio.io/">istio</a>: provides the underlying secure communication channel, and manages authentication, authorization, and encryption of service communication at scale</li><li><a href="https://github.com/google/gvisor">gVisor</a>: is a user-space kernel, written in Go, that implements a substantial portion of the Linux system surface</li><li><a href="https://www.vaultproject.io/docs/">vault</a>: secure, store and tightly control access to tokens, passwords, certificates, encryption keys for protecting secrets and other sensitive data</li></ul><p>For user authentication, I recommend checking out <a href="https://github.com/appscode/guard">guard</a> which will integrate with an existing authentication provider. If you’re already using Github teams to then this could be a no-brainer.</p><h3>Other Considerations</h3><p>I hope this has given you a good idea of deploying, networking, storage, and security for you to take the leap into deploying your own on-premise Kubernetes clusters. Like I mentioned above, your team will want to build proof-of-concept clusters, run conformance and performance tests, and really become experts on Kubernetes if you’re going to be using it to run production software.</p><p>I’ll leave you with a few other things your team should be thinking of:</p><ul><li>Externally backing up Kubernetes YAML, namespaces, and configuration files</li><li>Running applications across clusters in an active-active configuration to allow for zero-downtime updates</li><li>Running game days like deleting the CNI to measure and improve time-to-recovery</li></ul><p>This article is an adaptation of a presentation I gave for <a href="https://bisontrails.co/">BisonTrails</a> in New York City. Feel free to reach out for the original.</p><h3>Resources</h3><ul><li><a href="https://kubernetes.io/docs/concepts/overview/components/#master-components">https://kubernetes.io/docs/concepts/overview/components/#master-components</a></li><li><a href="https://cloud.google.com/kubernetes-engine/">https://cloud.google.com/kubernetes-engine/</a></li><li><a href="https://azure.microsoft.com/en-us/services/kubernetes-service/">https://azure.microsoft.com/en-us/services/kubernetes-service/</a></li><li><a href="https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/">https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/</a></li><li><a href="https://github.com/kubernetes-sigs/kubespray">https://github.com/kubernetes-sigs/kubespray</a></li><li><a href="https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner">https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner</a></li><li><a href="https://clouddocs.f5.com/containers/v2/kubernetes/">https://clouddocs.f5.com/containers/v2/kubernetes/</a></li><li><a href="https://github.com/purestorage/helm-charts">https://github.com/purestorage/helm-charts</a></li><li><a href="https://istio.io/">https://istio.io/</a></li><li><a href="https://github.com/google/gvisor">https://github.com/google/gvisor</a></li><li><a href="https://www.vaultproject.io/docs/">https://www.vaultproject.io/docs/</a></li><li><a href="https://github.com/appscode/guard">https://github.com/appscode/guard</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b36660ca6914" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/on-premise-kubernetes-clusters-b36660ca6914">On-premise Kubernetes Clusters</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Common Go Pitfalls]]></title>
            <link>https://medium.com/better-programming/common-go-pitfalls-a92197cd96d2?source=rss-e95ef4be7a2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/a92197cd96d2</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[database]]></category>
            <category><![CDATA[memory-leak]]></category>
            <dc:creator><![CDATA[Tyler Finethy]]></dc:creator>
            <pubDate>Thu, 24 Oct 2019 13:01:01 GMT</pubDate>
            <atom:updated>2019-10-25T15:48:12.073Z</atom:updated>
            <content:encoded><![CDATA[<h4>A few common mistakes and how to diagnose and fix them</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8XTRgJ-MFix4WF627cFCeA.png" /><figcaption>Avoid pitfalls while writing simple, reliable Go code</figcaption></figure><p>There’s a few reasons I love Golang:</p><ul><li>It’s a super small language (it has <a href="https://golang.org/ref/spec#Keywords">only 25 reserved keywords</a>)</li><li>Cross-compilation is a breeze</li><li>Creating a reliable HTTP(s) server is natively supported</li></ul><p>At its core, it’s a boring language, which is probably why awesome projects like <a href="https://github.com/avelino/awesome-go">Docker and Kubernetes</a> are written in it and companies with high performance and resiliency requirements, like <a href="https://blog.cloudflare.com/tag/go/">Cloudflare</a>, are using it.</p><p>Despite its ease of use, Go really requires attention to detail. If you don’t use the language as it’s intended it can break. It can be hard to diagnose and challenging to fix the mistake.</p><p>Here are a few common mistakes I’ve witnessed in production codebases, during code reviews, and made myself. Hopefully, this will make it easier for you to diagnose the same issues as you encounter them.</p><h3>HTTP Timeouts</h3><p>This first issue has an entire <a href="https://medium.com/@nate510/don-t-use-go-s-default-http-client-4804cb19f779">article written about it</a> but it’s still worth mentioning because the optimal solution can require some thought. It has to do with making outgoing HTTP requests using the default HTTP client.</p><p>To illustrate the problem, here’s a basic example of making a GET request to google.com:</p><pre>package main</pre><pre>import (<br>    &quot;io/ioutil&quot;<br>    &quot;log&quot;<br>    &quot;net/http&quot;<br>)</pre><pre>var (<br>    c = &amp;http.Client{}<br>)</pre><pre>func main() {<br>    req, err := http.NewRequest(&quot;GET&quot;, &quot;google.com&quot;, nil)<br>    if err != nil {<br>        log.Fatal(err)<br>    }</pre><pre>    res, err := c.Do(req)<br>    if err != nil {<br>        log.Fatal(err)<br>    }<br>    defer res.Body.Close()<br>    b, _ := ioutil.ReadAll(res.Body)<br>    ...<br>}<br></pre><p>As pointed out in the Don’t use Go’s default HTTP Client article, the default client doesn’t actually have a timeout. This means that code could hang indefinitely depending on the server or until the application is restarted.</p><p>So what’s the best way to resolve this issue?</p><p>While always defining your HTTP client with a sensible timeout is a good idea, &amp;http.Client{Timeout: time.Minute} you might also consider attaching a context to your request for a few added benefits:</p><ul><li>The ability to cancel ongoing requests</li><li>You can tune the timeout to specific requests</li></ul><p>The second benefit is especially important because if you have a few requests that you know are going to take a long time, say over an hour, you don’t want every request to wait an hour before timing out.</p><p>In the example above, adding a context would look something like this:</p><pre>ctx, cancel := context.WithTimeout(context.Background(), time.Minute)<br>defer cancel()</pre><pre>req = req.WithContext(ctx)</pre><pre>res, err := c.Do(req)<br>...</pre><p>If the allotted time is exceeded, the call to c.Do will result in a DeadlineExceeded error, making it easy to handle or retry. For more information on the context package, check out the <a href="https://golang.org/pkg/context/">documentation</a>.</p><h3>Database Connections</h3><p>I’ve had database connection issues crop up in almost every Go project I’ve been on. I think the hard thing for new gophers to wrap their heads around is that the sql.DB object is a concurrency-safe pool of connections instead of a single database connection. This means that if you forget to return your connections to the pool you can easily exhaust the number of connections and your application can grind to a halt.</p><p>For instance, the connection pool contains both Open and Idle connections which are configured through:</p><ul><li><a href="https://golang.org/pkg/database/sql/#DB.SetConnMaxLifetime">SetConnMaxLifetime</a>: the maximum amount of time a connection may be reused</li><li><a href="https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns">SetMaxIdleConns</a>: maximum number of connections in the idle connection pool</li><li><a href="https://golang.org/pkg/database/sql/#DB.SetMaxOpenConns">SetMaxOpenConns</a>: maximum number of open connections to the database</li></ul><p>Note that even if you configure the max open connections to 200, the application can still exhaust the number of open connections the database will accept, making a shutdown or restart necessary. You need to check the database settings or coordinate with whoever has the permissions to ensure you’re correctly setting these limits.</p><p>If you don’t configure a limit, your application can easily use all the connections the database will accept.</p><p>Back to exhausting the connection pool. When querying the database a lot of developers forget to close the *sql.Rows object. This leads to hitting the max connections limit and causes deadlock or high latency. Here’s a snippet of code showing this:</p><pre>package main</pre><pre>import (<br>    &quot;context&quot;<br>    &quot;database/sql&quot;<br>    &quot;fmt&quot;<br>    &quot;log&quot;<br>)</pre><pre>var (<br>    ctx context.Context<br>    db  *sql.DB<br>)</pre><pre>func main() {<br>    age := 27<br>    ctx, cancel := context.WithTimeout(context.Background(), time.Minute)<br>    defer cancel()</pre><pre>    rows, err := db.QueryContext(ctx, &quot;SELECT name FROM users WHERE age=?&quot;, age)<br>    if err != nil {<br>        log.Fatal(err)<br>    }</pre><pre>    for rows.Next() {<br>        var name string<br>        if err := rows.Scan(&amp;name); err != nil {<br>            log.Fatal(err)<br>        }<br>        fmt.Println(name)<br>    }<br>    ...</pre><pre>}</pre><p>You’ll notice, just as you can add context to an HTTP request, you can also add a context with a timeout to a database query (or an execution of a prepared statement, ping, etc.) But that’s not the problem.</p><p>As mentioned above we need to close the rows object to prevent further enumeration and release the connection back to the connection pool:</p><pre>rows, err := db.QueryContext(ctx, &quot;SELECT name FROM users WHERE age=?&quot;, age)<br>if err != nil {<br>    log.Fatal(err)<br>}<br>defer rows.Close()</pre><p>This becomes particularly difficult to spot if you’re passing open connections across functions and packages.</p><h3>Goroutine or Memory Leaks</h3><p>The last common mistake I’m going to cover here is Goroutine leaks. These can be tricky to detect but are usually caused by user error.</p><p>This happens often when using channels. For example:</p><pre>package main<br></pre><pre>func main() {<br>    c := make(chan error)<br>    go func() {<br>        for err := range c {<br>            if err != nil {<br>                panic(err)<br>            }<br>        }<br>    }()</pre><pre>    c &lt;- someFunc()<br>    ...</pre><pre>}</pre><p>If we don’t close the channel c or if someFunc() doesn’t return an error, the Goroutine we have initialized will hang until the program terminates.</p><p>Instead of enumerating the number of cases that can cause Goleaks, there are two methods I commonly deploy to detect and eliminate them.</p><p>The first method is to use a leak detector in your tests, like <a href="https://github.com/uber-go/goleak">Uber’s goleak library</a>. In practice this looks like this:</p><pre>func TestA(t *testing.T) {<br>    defer goleak.VerifyNone(t)<br>    // test logic here.<br>}</pre><p>This will verify, after a grace period of 30 seconds to allow for graceful shutdown, that there are no unexpected Goroutines running at the end of a test.</p><p>The other method is to use the <a href="https://blog.golang.org/profiling-go-programs">Go profiler</a> on a running instance of your application and look at the number of active Goroutines. One way to do this is to add the <a href="https://golang.org/pkg/net/http/pprof/">net/http/pprof library</a> and click the Goroutine profile.</p><p>You can enable it by adding this:</p><pre>import _ &quot;net/http/pprof&quot;</pre><pre>func someFunc() {<br>    go func() {<br>        log.Println(http.ListenAndServe(&quot;localhost:6060&quot;, nil))</pre><pre>    }<br>}</pre><p>This will enable pprof on port 6060. For especially bad leaks, you can refresh and see the number of goroutines increase. For more subtle leaks, read through the profile and look for instances of functions sticking around when they shouldn’t. The profile page will look something like this:</p><pre>goroutine profile: total 39<br>2 @ 0x43cf10 0x44ca6b 0x980600 0x46b301<br>#	0x9805ff	database/sql.(*DB).connectionCleaner+0x36f	/usr/local/go/src/database/sql/sql.go:950<br><br>2 @ 0x43cf10 0x44ca6b 0x980b18 0x46b301<br>#	0x980b17	database/sql.(*DB).connectionOpener+0xe7	/usr/local/go/src/database/sql/sql.go:1052<br><br>2 @ 0x43cf10 0x44ca6b 0x980c4b 0x46b301<br>#	0x980c4a	database/sql.(*DB).connectionResetter+0xfa	/usr/local/go/src/database/sql/sql.go:1065</pre><pre>...</pre><p>If your application is idle and you’re seeing a lot of total Goroutine’s that’s a good indication that something is going wrong. After identifying where the leak is, I still recommend using a leak detector in the tests to ensure the issue is resolved.</p><h3>Conclusion</h3><p>Hopefully knowing about and seeing some examples of these common mistakes will help you identify and fix them more quickly. Obviously there are a number of other common mistakes, such as:</p><ul><li>Race conditions</li><li>Deadlocks</li><li>Error swallowing</li></ul><p>These can be found and fixed through similar techniques, like using the <a href="https://blog.golang.org/race-detector">go race detector,</a> writing tests, or using the go profiler.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a92197cd96d2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/common-go-pitfalls-a92197cd96d2">Common Go Pitfalls</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The GOPATH is for everyone]]></title>
            <link>https://medium.com/swlh/the-gopath-is-for-everyone-e17206216dfa?source=rss-e95ef4be7a2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/e17206216dfa</guid>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[gopath]]></category>
            <category><![CDATA[configuration-software]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Tyler Finethy]]></dc:creator>
            <pubDate>Thu, 17 Oct 2019 13:21:01 GMT</pubDate>
            <atom:updated>2019-10-24T13:27:48.514Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5TChMOpqjoswD1j1.png" /><figcaption>The Go tool-chain can be useful even outside of Go development</figcaption></figure><h3>TL;DR</h3><p>The command go get will organize your code into an easy to follow directory structure that you can use across all your work-spaces. Give it a try even if you’re not a gopher.</p><p><strong>Example:</strong> go get github.com/golang/go will clone the repository and put it at $GOPATH/go/github.com/golang/go where GOPATH usually defaults to your home directory.</p><h3>Background</h3><p>When I started using Golang 3 years ago, I came from a world of Python, PHP, and NodeJS where every time I created a new repository I would have to think about where it was going to go. This would usually result in directory structures like:</p><pre>.<br>├── repo1<br>├── myCode<br>│   ├── repo2<br>│   ├── repo3<br>│   └── repo4<br>├── myOrg<br>│   ├── repo5<br>│   ├── repo6<br>│   └── repo7<br>├── opensourceOrg<br>│   ├── repo10<br>│   ├── repo8<br>│   └── repo9<br>└── scratch<br>    ├── repo11<br>    ├── repo12<br>    └── repo13</pre><p>Maybe I’m not disciplined enough, but this tree could look wildly different depending on my mood, the amount of coffee I’ve had, or what task I’m thinking about and working on.</p><p>There’s actually information lost here:</p><ul><li>What organization/user does repo1 belong to?</li><li>Are we sure that every repository in myCode is ours?</li><li>What version control system do these repositories use?</li></ul><p>As I started learning go, I absolutely hated the idea of the GOPATH, some language is going to tell me how to organize my code? Ridiculous, but I set it up to get up and running with Golang. Now even across my non-Go projects I can’t imagine doing it any other way.</p><h3>How does the GOPATH help?</h3><p>The GOPATH is an environment variable that specifies where the Golang tool chain should put and look for Go code (before the adoption of <a href="https://golang.org/cmd/go/#hdr-Vendor_Directories">vendoring</a> and <a href="https://github.com/golang/go/wiki/Modules">gomod</a>). There’s a lot of reasons why the community didn’t like the GOPATH as a global package management system, but I won’t get into that here.</p><p>If you have go installed, the get command comes out of the box. For a non-Go project this usually looks like:</p><pre>&gt; go get github.com/tylfin/geospy<br>package github.com/tylfin/geospy: no Go files in /Users/tylerfinethy/go/src/github.com/tylfin/geospy</pre><p>Which will create the tree-structure:</p><pre>go/<br>├── bin<br>├── pkg<br>└── src<br>    └── github.com<br>        └── tylfin<br>            └── geospy</pre><p>For multiple repositories, organizations, and version control systems this will look like:</p><pre>go/<br>├── bin<br>├── pkg<br>└── src<br>    ├── github.com<br>    │   ├── tylfin<br>    │   │   ├── dynatomic<br>    │   │   └── geospy<br>    │   └── uudashr<br>    │       └── gopkgs<br>    └── golang.org<br>        └── x<br>            └── tools</pre><p>That’s it. Go will create a deterministic structure that answers all the questions above, and will be the same across every system.</p><p>While I understand it might be suspect to use an entire programming language to organize your code, it’s a quick install and works well enough for me that I’ll be using it for the foreseeable future. I recommend it to all my colleagues as well.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e17206216dfa" width="1" height="1" alt=""><hr><p><a href="https://medium.com/swlh/the-gopath-is-for-everyone-e17206216dfa">The GOPATH is for everyone</a> was originally published in <a href="https://medium.com/swlh">The Startup</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>