<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Taq Karim</title>
    <description>The latest articles on Forem by Taq Karim (@taqkarim).</description>
    <link>https://forem.com/taqkarim</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F292047%2Fe3a1775c-c8ea-4ade-9180-6021606e4688.png</url>
      <title>Forem: Taq Karim</title>
      <link>https://forem.com/taqkarim</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/taqkarim"/>
    <language>en</language>
    <item>
      <title>You might not be using json.Decoder correctly in golang</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Mon, 25 Jan 2021 02:58:11 +0000</pubDate>
      <link>https://forem.com/taqkarim/you-might-not-be-using-json-decoder-correctly-in-golang-12mb</link>
      <guid>https://forem.com/taqkarim/you-might-not-be-using-json-decoder-correctly-in-golang-12mb</guid>
      <description>&lt;p&gt;TL;DR: prevailing "secondary source" wisdom (ie: blog posts) about &lt;code&gt;json.Decoder&lt;/code&gt; don't demonstrate the proper way to use it.&lt;/p&gt;




&lt;p&gt;This post is a follow up to my (kinda lengthy) &lt;a href="https://mottaquikarim.github.io/dev/posts/is-json.decoder-broken-in-golang/" rel="noopener noreferrer"&gt;deep dive&lt;/a&gt; into what I &lt;em&gt;thought&lt;/em&gt; was a bug in golang's &lt;code&gt;json.Decoder&lt;/code&gt; pkg.&lt;/p&gt;

&lt;p&gt;Instead, I realized that generally speaking, &lt;code&gt;json.Decoder&lt;/code&gt; can be misunderstood - which &lt;em&gt;may&lt;/em&gt; lead to unintended consequences. In this post, I will demonstrate a safer pattern that ought to be used instead of the prevailing wisdom.&lt;/p&gt;

&lt;h2&gt;
  
  
  Googling: &lt;strong&gt;"json.decoder example golang"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I ran a few google searches queries using some permutation of the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;json.decoder example golang&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The results were your standard mix of documentation from &lt;code&gt;golang.org&lt;/code&gt;, blog posts on &lt;code&gt;medium.com&lt;/code&gt;/random mom&amp;amp;pop devsites (like this one!), and a few &lt;code&gt;stackoverflow&lt;/code&gt; threads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmottaquikarim.github.io%2Fdev%2Fimg%2Fgoogle-json-decoder.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmottaquikarim.github.io%2Fdev%2Fimg%2Fgoogle-json-decoder.png" alt="Google Search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fortunately, results from &lt;code&gt;golang.org&lt;/code&gt; are highly ranked - while it may be a bit harder to parse through golang's src code, the documentation is fairly thorough and more importantly: &lt;strong&gt;correct&lt;/strong&gt;. &lt;em&gt;(Personally, I would have preferred some additional context in the docs expounding on some of the gotchas I discuss on my other post but I digress)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some of the threads I observed in Stack Overflow that referenced &lt;code&gt;json.Decoder&lt;/code&gt; pulled directly from the docs (and therefore were also correct). Other's (probably) pulled from medium/other blog post sites similar to the ones I found googling around and were inaccurate/advocating incorrect usage.&lt;/p&gt;

&lt;p&gt;For example, on Medium, et al - I saw a wide array of posts (such as &lt;a href="https://medium.com/what-i-talk-about-when-i-talk-about-technology/go-code-snippet-json-encoder-and-json-decoder-818f81864614" rel="noopener noreferrer"&gt;this&lt;/a&gt;, &lt;a href="https://itnext.io/welcome-to-just-enough-go-7dbef7e30188" rel="noopener noreferrer"&gt;this&lt;/a&gt;, &lt;a href="https://stackoverflow.com/q/28814366" rel="noopener noreferrer"&gt;this&lt;/a&gt; or &lt;a href="https://medium.com/rungo/working-with-json-in-go-7e3a37c5a07b" rel="noopener noreferrer"&gt;this&lt;/a&gt;) that suggested using &lt;code&gt;json.Decoder&lt;/code&gt; in some way, shape, or form similarly to this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;jsonData&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;`{
"email":"abhirockzz@gmail.com",
"username":"abhirockzz",
"blogs":[
    {"name":"devto","url":"https://dev.to/abhirockzz/"},
    {"name":"medium","url":"https://medium.com/@abhishek1987/"}
]}`&lt;/span&gt;

    &lt;span class="n"&gt;jsonDataReader&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonDataReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="n"&gt;Profile&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(Example pulled from &lt;a href="https://itnext.io/welcome-to-just-enough-go-7dbef7e30188" rel="noopener noreferrer"&gt;Tutorial: How to work with JSON data in Go&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;On the surfact, this code looks sound. I forklifted the src into &lt;a href="https://play.golang.org/p/qy-7BIx_FlA" rel="noopener noreferrer"&gt;go playground&lt;/a&gt; and ran it. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;jsonData&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;`{
"email":"abhirockzz@gmail.com",
"username":"abhirockzz",
"blogs":[
    {"name":"devto","url":"https://dev.to/abhirockzz/"},
    {"name":"medium","url":"https://medium.com/@abhishek1987/"}
]}`&lt;/span&gt;

    &lt;span class="n"&gt;jsonDataReader&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonDataReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(Note, changed &lt;code&gt;profile&lt;/code&gt; to &lt;code&gt;map[string]interface{}&lt;/code&gt; to make the code run)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;...It works! Great. But, what happens if we fubar the JSON string?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;jsonData&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;`{
"email":"abhirockzz@gmail.com",
"username":"abhirockzz",
"blogs":[
    {"name":"devto","url":"https://dev.to/abhirockzz/"},
    {"name":"medium","url":"https://medium.com/@abhishek1987/"}
]}THIS IS INTENTIONALLY MALFORMED NOW`&lt;/span&gt;

    &lt;span class="n"&gt;jsonDataReader&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonDataReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(&lt;a href="https://play.golang.org/p/MyM1A8Y51Jc" rel="noopener noreferrer"&gt;playground&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;...It works!&lt;/p&gt;

&lt;p&gt;Wait...&lt;strong&gt;WTF?!&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This code should &lt;em&gt;not&lt;/em&gt; work at all! Our JSON string is clearly malformed and we expect - based on the logic - the code to panic.&lt;/p&gt;

&lt;p&gt;This is the entire issue in a nutshell. I expound in detail in my other post but in one (kinda long) sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;json.Decoder.Decode&lt;/code&gt; was implemented for parsing &lt;em&gt;streaming&lt;/em&gt; JSON data, meaning it will &lt;strong&gt;always&lt;/strong&gt; traverse the JSON string until it finds a satisfactory, closing bracket (I use the term &lt;em&gt;satisfactory&lt;/em&gt; here because it does use a stack to keep track of inner brackets).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, in order to detect the malformed json, we must actually run this logic in a loop - like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;jsonData&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;`{
"email":"abhirockzz@gmail.com",
"username":"abhirockzz",
"blogs":[
    {"name":"devto","url":"https://dev.to/abhirockzz/"},
    {"name":"medium","url":"https://medium.com/@abhishek1987/"}
]}THIS IS INTENTIONALLY MALFORMED NOW`&lt;/span&gt;

    &lt;span class="n"&gt;jsonDataReader&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonDataReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(&lt;a href="https://play.golang.org/p/TqIiLzNdtpi" rel="noopener noreferrer"&gt;playground&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Note the key diff here:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// ...&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;From the golang docs, this example says it best:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="c"&gt;// This example uses a Decoder to decode a stream of distinct JSON values.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ExampleDecoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;jsonStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`
    {"Name": "Ed", "Text": "Knock knock."}
    {"Name": "Sam", "Text": "Who's there?"}
    {"Name": "Ed", "Text": "Go fmt."}
    {"Name": "Sam", "Text": "Go fmt who?"}
    {"Name": "Ed", "Text": "Go fmt yourself!"}
`&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;dec&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jsonStream&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EOF&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// Output:&lt;/span&gt;
    &lt;span class="c"&gt;// Ed: Knock knock.&lt;/span&gt;
    &lt;span class="c"&gt;// Sam: Who's there?&lt;/span&gt;
    &lt;span class="c"&gt;// Ed: Go fmt.&lt;/span&gt;
    &lt;span class="c"&gt;// Sam: Go fmt who?&lt;/span&gt;
    &lt;span class="c"&gt;// Ed: Go fmt yourself!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(&lt;a href="https://golang.org/src/encoding/json/example_test.go#L57" rel="noopener noreferrer"&gt;sauce&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this usage, we create a new &lt;code&gt;json.Decoder&lt;/code&gt; instance from the &lt;code&gt;NewDecoder&lt;/code&gt; method and then continually loop and try to decode a chunk of our JSON string until we detect the end of the string (sucessfully breaking out of the loop) or an error.&lt;/p&gt;

&lt;p&gt;I would take this a step further and only prefer to use &lt;code&gt;json.Decoder&lt;/code&gt; when I am specifically working with streaming JSON data.&lt;/p&gt;

&lt;p&gt;At any rate, this the The Way. Please keep this in mind going forward should you choose to use &lt;code&gt;json.Decoder&lt;/code&gt; for your JSON string parsing needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A big caveat I'd like to point out is that I did not perform any rigorous analysis of golang examples in the wild when I was inspired to write this post. My analysis comes largely from anecdotal examples I observed while researching my other deep dive article about the nature of &lt;code&gt;json.scanner&lt;/code&gt; and &lt;code&gt;json.Decoder.Decode&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I certianly am not being critical of the medium/mom&amp;amp;pop blogs I linked to earlier, instead I am merely pointing out that it is &lt;em&gt;very&lt;/em&gt; easy to assume that the trivial usage of &lt;code&gt;json.Decoder.Decode&lt;/code&gt; presented on those posts is generally correct when in actuality this is not the case.&lt;/li&gt;
&lt;li&gt;I think someone (maybe me? perhaps you?) ought to open a PR against godocs to clarify gotchas/differences between &lt;code&gt;json.Decoder&lt;/code&gt; usage vs &lt;code&gt;json.Unmarshal&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;PS: this article is x-posted from my &lt;a href="https://mottaquikarim.github.io/dev/posts/you-might-not-be-using-json.decoder-correctly-in-golang/" rel="noopener noreferrer"&gt;dev blog&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>json</category>
    </item>
    <item>
      <title>Custom Args in Makefile</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Sun, 03 Jan 2021 05:59:04 +0000</pubDate>
      <link>https://forem.com/taqkarim/custom-args-in-makefile-3mof</link>
      <guid>https://forem.com/taqkarim/custom-args-in-makefile-3mof</guid>
      <description>&lt;p&gt;TL;DR: use &lt;code&gt;$(eval ARGS=${ARGS} [some additional arg])&lt;/code&gt; within a make target to build custom argument sequences for commands wrapped by make targets - like &lt;code&gt;make test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I expound further on the usecase and methodology below 👇&lt;/p&gt;




&lt;p&gt;I like to wrap common tasks, such as running unit tests, around a make target.&lt;/p&gt;

&lt;p&gt;This way, I can minimize the length of the command I need to run (ie: &lt;code&gt;make test&lt;/code&gt; vs &lt;code&gt;go test ./... -race -coverprofile=c.out&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;However, as a project grows, it becomes necessary or just preferable to support a variety of permutations of the above. &lt;/p&gt;

&lt;p&gt;(Note: I am not advocating that one &lt;em&gt;ought&lt;/em&gt; to use make targets in this manner, just that if this route is chosen, there are patterns available to simplify things a bit).&lt;/p&gt;

&lt;p&gt;For the sake of go, here are a few potential tests I'd like to be able to run:&lt;/p&gt;

&lt;h3&gt;
  
  
  Run tests w/&lt;a href="https://golang.org/doc/articles/race_detector.html"&gt;race conditions&lt;/a&gt; check
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-race&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run tests in &lt;a href="https://golang.org/pkg/testing/#Short"&gt;"short"&lt;/a&gt; mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-short&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run tests w/verbose results in terminal
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run tests for a specific package
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./my_awesome_pkg/...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run a specific test func in a specific package
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./my_awesome_pkg/... &lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;TestFoobar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A better way
&lt;/h2&gt;

&lt;p&gt;Of course, the main issue that comes up here is: what if we wanted to mix and match some of these opts? (For instance, we might want to run tests on a specific package with verbose test output with race condition checks enabled.)&lt;/p&gt;

&lt;p&gt;Again, assuming we'd like to reuse the &lt;code&gt;make test&lt;/code&gt; interface, our make target can get really messy really quickly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;#   Usage:
#       make test-dev
#       make test-dev package=my_awesome_pkg
&lt;/span&gt;&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="k"&gt;ifdef&lt;/span&gt; &lt;span class="nv"&gt;package &lt;/span&gt;
    go &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; ./&lt;span class="nv"&gt;${package}&lt;/span&gt;/... &lt;span class="nt"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c.out
&lt;span class="k"&gt;else&lt;/span&gt;
    go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c.out
&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we only support two use cases, run all tests in a single package and run all tests in all packages in current working directory. Even so, as you can probably see, it is easy to miss stuff (for instance, package tests have the verbose flag) and repetition can start to seep in (note the -coverprofile arg in both conditions).&lt;/p&gt;

&lt;p&gt;An alternative (and personally, preferable approach might be):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;#   Usage:
#       make test norace=1
#           Expl: run WITHOUT race conditions
#       make test ftest=1
#           Explt: run WITH "ftests", long lived non unit tests
#       make test v=1
#           Explt: run in verbose mode
#       make test package=my_awesome_pkg
#           Explt: run tests in a single package only
#           NOTE: if omitted, will run ALL tests
#       make test package=my_awesome_pkg func=TestViews
#           Explt: run a single test func (needs package as well)
&lt;/span&gt;&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="nv"&gt;ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# by default, run with race conditions
&lt;/span&gt;&lt;span class="k"&gt;ifndef&lt;/span&gt; &lt;span class="nv"&gt;norace&lt;/span&gt;
    &lt;span class="err"&gt;$(eval&lt;/span&gt; &lt;span class="nv"&gt;ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${ARGS}&lt;/span&gt; &lt;span class="nt"&gt;-race&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;span class="c"&gt;# by default, run in "short" mode
&lt;/span&gt;&lt;span class="k"&gt;ifndef&lt;/span&gt; &lt;span class="nv"&gt;ftest&lt;/span&gt;
    &lt;span class="err"&gt;$(eval&lt;/span&gt; &lt;span class="nv"&gt;ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${ARGS}&lt;/span&gt; &lt;span class="nt"&gt;-short&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;span class="k"&gt;ifdef&lt;/span&gt; &lt;span class="nv"&gt;v&lt;/span&gt;
    &lt;span class="err"&gt;$(eval&lt;/span&gt; &lt;span class="nv"&gt;ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${ARGS}&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;span class="c"&gt;# if package provided, run the package
&lt;/span&gt;&lt;span class="k"&gt;ifdef&lt;/span&gt; &lt;span class="nv"&gt;package&lt;/span&gt;
    &lt;span class="err"&gt;$(eval&lt;/span&gt; &lt;span class="nv"&gt;ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${ARGS}&lt;/span&gt; ./&lt;span class="nv"&gt;${package}&lt;/span&gt;/...&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="err"&gt;$(eval&lt;/span&gt; &lt;span class="nv"&gt;ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${ARGS}&lt;/span&gt; ./...&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;span class="c"&gt;# if func provided, run the func only
&lt;/span&gt;&lt;span class="k"&gt;ifdef&lt;/span&gt; &lt;span class="nv"&gt;func&lt;/span&gt;
    &lt;span class="err"&gt;$(eval&lt;/span&gt; &lt;span class="nv"&gt;ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${ARGS}&lt;/span&gt; &lt;span class="nt"&gt;-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${func}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
    &lt;span class="err"&gt;go&lt;/span&gt; &lt;span class="err"&gt;test&lt;/span&gt; &lt;span class="err"&gt;${ARGS}&lt;/span&gt; &lt;span class="nv"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this approach, we use &lt;code&gt;$(eval ARGS=${ARGS} [append an arg]&lt;/code&gt; to build the actual args for our &lt;code&gt;go test&lt;/code&gt; invocation based on make target args.&lt;/p&gt;

&lt;p&gt;What's nice about this approach is we can choose to make certain things default vs non default by leveraging make's &lt;code&gt;ifdef&lt;/code&gt; and &lt;code&gt;ifndef&lt;/code&gt; (if not defined) conditionals.&lt;/p&gt;

&lt;p&gt;The last line is the actual test invocation and if we wanted to, we could always echo &lt;code&gt;${ARGS}&lt;/code&gt; right before for debugging purposes, etc.&lt;/p&gt;

&lt;p&gt;I really like this approach and have started using it in a lot of my makefile target patterns where I leverage &lt;code&gt;make test&lt;/code&gt; for dev-ing or ci related tasks. While I've walked through a golang based usecase, this pattern can be used for more or less any make target usage (though personally, I really only use this for running tests during dev/ci).&lt;/p&gt;

</description>
      <category>testing</category>
      <category>go</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Integrating Code Climate w/go pkgs</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Fri, 01 Jan 2021 14:28:32 +0000</pubDate>
      <link>https://forem.com/taqkarim/integrating-code-climate-w-go-pkgs-2on6</link>
      <guid>https://forem.com/taqkarim/integrating-code-climate-w-go-pkgs-2on6</guid>
      <description>&lt;p&gt;TL; DR: When integrating golang code coverage with Code Climate, be sure to set the &lt;code&gt;--prefix&lt;/code&gt; arg (set it to your pkg github prefix, ie: "github.com/mottaquikarim/esquerydsl") in the &lt;code&gt;after-build&lt;/code&gt; stage in order for your src code to be recognized by the test reporter.&lt;/p&gt;

&lt;p&gt;If ^^ that didn't make sense, read on below for the full background 👍&lt;/p&gt;




&lt;p&gt;I've recently published a golang pkg, called &lt;a href="https://github.com/mottaquikarim/esquerydsl"&gt;esquerydsl&lt;/a&gt;, which facillitates safe construction of elasticsearch queries in golang.&lt;/p&gt;

&lt;p&gt;In order to ensure future stability, I wanted to integrate &lt;a href="https://codeclimate.com/"&gt;Code Climate&lt;/a&gt; for tracking maintainability and test coverage.&lt;/p&gt;

&lt;p&gt;I've used CC before on python projects but never for go and while integrating, I ran into a gotcha that I thought I ought to document / share.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0: Write and run some tests!
&lt;/h2&gt;

&lt;p&gt;I won't expound on the actual source code and instead focus on how to run and export test + results to code climate.&lt;/p&gt;

&lt;p&gt;Running tests in go is super easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I prefer to work in docker so I usually run the above as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/app golang:1.15 go &lt;span class="nb"&gt;test&lt;/span&gt; ./...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(All examples here on out will be run in docker)&lt;/p&gt;

&lt;p&gt;Let's break this down before continuing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker run&lt;/code&gt;: within a docker container, let's run some stuff&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-w /app&lt;/code&gt;: our "working directory" will be the &lt;code&gt;app&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v ${PWD}:/app&lt;/code&gt;: we volume mount our current working directory into the "working directory" in the container. This is a nice trick for quickly running tests on source code you are writing during dev&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;golang:1.15&lt;/code&gt;: the image we want to run - in this case, golang v1.15&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;go test ./...&lt;/code&gt;: finally, the command we want to run in our docker container - which is of course our go test command&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Track code coverage
&lt;/h3&gt;

&lt;p&gt;Tracking code coverage in golang is also super easy. We just need to add a single arg to your &lt;code&gt;go test&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-coverprofile&lt;/code&gt; arg tells go where to publish the test coverage results, which can be parsed later on to help visualize your source code's coverage results.&lt;/p&gt;

&lt;p&gt;Putting it all together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/app golang:1.15 go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, there is a file called &lt;code&gt;c.out&lt;/code&gt; which is available in your current working directory that encodes your line-by-line test coverage data. Great! All we have to do now is upload this to code climate and we are golden.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sidebar: generating code coverage results as HTML
&lt;/h3&gt;

&lt;p&gt;This is a proper tangent, so feel free to ignore. &lt;/p&gt;




&lt;p&gt;I find it super useful to understand/view which lines I missed in my unit tests. While line by line test coverage does not necessarily guarantee stability, I find it to be a useful benchmark for knowing when to &lt;em&gt;stop&lt;/em&gt; writing unit tests (somewhere around 90+% is my 👍 point)&lt;/p&gt;

&lt;p&gt;To visualize this in go, run the following after your tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/app golang:1.15 go tool cover &lt;span class="nt"&gt;-html&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c.out &lt;span class="nt"&gt;-o&lt;/span&gt; coverage.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;coverage.html&lt;/code&gt; can be opened in your browser to walk through your src code and it will visually indicate which lines have been covered by your tests and which lines have been missed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started with CodeClimate
&lt;/h3&gt;

&lt;p&gt;I'm going to skip this because otherwise this post will get &lt;em&gt;long&lt;/em&gt;. My assumption is folks reading this already have a CC Quality account and have a (golang!) repo set up for usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Downloading the test reporter
&lt;/h2&gt;

&lt;p&gt;Download and run the Code Climate test reporter. Of course, we want to do this in our docker container (there are plenty of examples available on how to do this "bare" around the internet). For me, this entailed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. download CC test reported&lt;/span&gt;
&lt;span class="nv"&gt;CC_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64
docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/app golang:1.15 &lt;span class="se"&gt;\&lt;/span&gt;
    /bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"curl -L &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CC_URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; ./cc-test-reporter"&lt;/span&gt;

&lt;span class="c"&gt;# 2. update perms&lt;/span&gt;
docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/app golang:1.15 &lt;span class="nb"&gt;chmod&lt;/span&gt; +x ./cc-test-reporter

&lt;span class="c"&gt;# 3. run before build&lt;/span&gt;
docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/app &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CC_TEST_REPORTER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CC_TEST_REPORTER_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    golang:1.15 ./cc-test-reporter before-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The three main parts here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We need to download the test reporter, which is available to &lt;code&gt;curl&lt;/code&gt; via the &lt;code&gt;CC_URL&lt;/code&gt;. I run this in two steps in a single docker &lt;code&gt;run&lt;/code&gt; command which is why I have the &lt;code&gt;/bin/bash -c "...steps to run..."&lt;/code&gt; line (you can do it in two lines if needed as well)&lt;/li&gt;
&lt;li&gt;Update perms to make this download executable. Notice that I run &lt;code&gt;chmod&lt;/code&gt; on the renamed file &lt;code&gt;cc-test-reporter&lt;/code&gt; (you can call this whatever you want) within the container itself.&lt;/li&gt;
&lt;li&gt;Finally, run &lt;code&gt;before-build&lt;/code&gt; which sets up the test reporter to send the coverage data. The &lt;code&gt;CC_TEST_REPORTER_ID&lt;/code&gt; is significant - this is how CC authenticates your repo's code coverage as really from you. I have it as an envvar since it should not be committed to code anywhere&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 2: Running the tests with code coverage
&lt;/h2&gt;

&lt;p&gt;This step is easy, basically Step 0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/app golang:1.15 go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Running the after build
&lt;/h2&gt;

&lt;p&gt;This is where I ran into my issue. The easy / documented step is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# upload data to CC
docker run -w /app -v ${PWD}:/app \
    -e CC_TEST_REPORTER_ID=${CC_TEST_REPORTER_ID} \
    golang:1.15 ./cc-test-reporter after-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is pretty standard at this point: we run the &lt;code&gt;cc-test-reporter&lt;/code&gt; with the &lt;code&gt;after-build&lt;/code&gt; arg as directed by CodeClimate. And, we pass along the &lt;code&gt;CC_TEST_REPORTER_ID&lt;/code&gt; to property identify ourselves. However, the kicker is the command above &lt;em&gt;alone&lt;/em&gt; will not work!&lt;/p&gt;

&lt;p&gt;When I ran the line above for my &lt;code&gt;esquerydsl&lt;/code&gt; package (heads up, I temporarily added the &lt;code&gt;--debug&lt;/code&gt; flag too), I ended up with the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2020-12-31T19:52:57Z"&lt;/span&gt; &lt;span class="nv"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;error &lt;span class="nv"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"failed to read file github.com/mottaquikarim/esquerydsl/esquerydsl.go&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;open github.com/mottaquikarim/esquerydsl/esquerydsl.go: no such file or directory"&lt;/span&gt;
Error: open github.com/mottaquikarim/esquerydsl/esquerydsl.go: no such file or directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fix, it looks like the &lt;code&gt;--prefix&lt;/code&gt; is required, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:/app &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CC_TEST_REPORTER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CC_TEST_REPORTER_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    golang:1.15 ./cc-test-reporter after-build &lt;span class="nt"&gt;--prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;github.com/mottaquikarim/esquerydsl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;--prefix=github.com/mottaquikarim/esquerydsl&lt;/code&gt;. The &lt;em&gt;full&lt;/em&gt; package prefix url is needed for this to work. Once I added this arg, I was able to upload code coverage stats for my pkg just fine. (Check it out &lt;a href="https://codeclimate.com/github/mottaquikarim/esquerydsl"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;I have this thing tied up in a neat bow at this point and thought I'd share. I use make targets to handle running this in Github Actions. I'll share the recipes below in the hopes maybe it can help someone else in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Makefile&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="c"&gt;# Definitions
&lt;/span&gt;&lt;span class="nv"&gt;ROOT&lt;/span&gt;                    &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nv"&gt;$(PWD)&lt;/span&gt;
&lt;span class="nv"&gt;GO_HTML_COV&lt;/span&gt;             &lt;span class="o"&gt;:=&lt;/span&gt; ./coverage.html
&lt;span class="nv"&gt;GO_TEST_OUTFILE&lt;/span&gt;         &lt;span class="o"&gt;:=&lt;/span&gt; ./c.out
&lt;span class="nv"&gt;GOLANG_DOCKER_IMAGE&lt;/span&gt;     &lt;span class="o"&gt;:=&lt;/span&gt; golang:1.15
&lt;span class="nv"&gt;GOLANG_DOCKER_CONTAINER&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; goesquerydsl-container
&lt;span class="nv"&gt;CC_TEST_REPORTER_ID&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nv"&gt;${CC_TEST_REPORTER_ID}&lt;/span&gt;
&lt;span class="nv"&gt;CC_PREFIX&lt;/span&gt;       &lt;span class="o"&gt;:=&lt;/span&gt; github.com/mottaquikarim/esquerydsl

&lt;span class="c"&gt;#   Usage:
#       make test
&lt;/span&gt;&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;${ROOT}&lt;/span&gt;:/app &lt;span class="nv"&gt;${GOLANG_DOCKER_IMAGE}&lt;/span&gt; go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${GO_TEST_OUTFILE}&lt;/span&gt;
    docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;${ROOT}&lt;/span&gt;:/app &lt;span class="nv"&gt;${GOLANG_DOCKER_IMAGE}&lt;/span&gt; go tool cover &lt;span class="nt"&gt;-html&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${GO_TEST_OUTFILE}&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;${GO_HTML_COV}&lt;/span&gt;

&lt;span class="c"&gt;# custom logic for code climate, gross but necessary
&lt;/span&gt;&lt;span class="nl"&gt;_before-cc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="c"&gt;# download CC test reported&lt;/span&gt;
    docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;${ROOT}&lt;/span&gt;:/app &lt;span class="nv"&gt;${GOLANG_DOCKER_IMAGE}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        /bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="s2"&gt;"curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 &amp;gt; ./cc-test-reporter"&lt;/span&gt;

    &lt;span class="c"&gt;# update perms
&lt;/span&gt; &lt;span class="nl"&gt;docker run -w /app -v ${ROOT}&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;/app ${GOLANG_DOCKER_IMAGE} chmod +x ./cc-test-reporter&lt;/span&gt;

    &lt;span class="c"&gt;# run before build
&lt;/span&gt; &lt;span class="nl"&gt;docker run -w /app -v ${ROOT}&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;/app &lt;/span&gt;\
&lt;span class="nf"&gt;        -e CC_TEST_REPORTER_ID=${CC_TEST_REPORTER_ID} &lt;/span&gt;\
&lt;span class="nf"&gt;       ${GOLANG_DOCKER_IMAGE} ./cc-test-reporter before-build&lt;/span&gt;

&lt;span class="nl"&gt;_after-cc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="c"&gt;# handle custom prefix&lt;/span&gt;
    &lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="nv"&gt;PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${CC_PREFIX}&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ifdef&lt;/span&gt; &lt;span class="nv"&gt;prefix&lt;/span&gt;
    &lt;span class="nf"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="nv"&gt;PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${prefix}&lt;/span&gt;&lt;span class="nf"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
    &lt;span class="c"&gt;# upload data to CC&lt;/span&gt;
    docker run &lt;span class="nt"&gt;-w&lt;/span&gt; /app &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;${ROOT}&lt;/span&gt;:/app &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CC_TEST_REPORTER_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;${CC_TEST_REPORTER_ID}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nv"&gt;${GOLANG_DOCKER_IMAGE}&lt;/span&gt; ./cc-test-reporter after-build &lt;span class="nt"&gt;--prefix&lt;/span&gt; &lt;span class="nv"&gt;${PREFIX}&lt;/span&gt;

&lt;span class="c"&gt;# this runs tests with cc reporting built in
&lt;/span&gt;&lt;span class="nl"&gt;test-ci&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_before-cc test _after-cc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;Github Action&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;I saved this file in: &lt;code&gt;.github/workflows/run-build.yml&lt;/code&gt; and in my repo secrets, I saved my &lt;code&gt;CC_TEST_REPORTER_ID&lt;/code&gt; so that I can export it as envvar on build time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Status&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout master&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unit tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;make clean test-ci&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;CC_TEST_REPORTER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CC_TEST_REPORTER_ID }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that running &lt;code&gt;make test-ci&lt;/code&gt; will run tests with the codeclimate reporter running and &lt;code&gt;make test&lt;/code&gt; just runs normal unit tests for dev/debugging.&lt;/p&gt;

&lt;p&gt;The results of the configs above should be viewable in the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mottaquikarim/esquerydsl/runs/1631500119?check_suite_focus=true"&gt;Github Action run ex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mottaquikarim/esquerydsl"&gt;README ex&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Generate Lambda Layer Artifacts w/Docker</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Mon, 21 Dec 2020 13:55:01 +0000</pubDate>
      <link>https://forem.com/taqkarim/generate-lambda-layer-artifacts-w-docker-7a</link>
      <guid>https://forem.com/taqkarim/generate-lambda-layer-artifacts-w-docker-7a</guid>
      <description>&lt;p&gt;This post (and accompanying code) was inspired by &lt;a href="https://towardsdatascience.com/how-to-install-python-packages-for-aws-lambda-layer-74e193c76a91"&gt;this&lt;/a&gt; tutorial and a need to easily generate lambda layer artifacts for a grad course I teach at Baruch University.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/mottaquikarim/pkglambdalayer"&gt;Github&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Generate a lambda layer artifact for python using this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; requirements.txt
&lt;span class="nv"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;2.24.0
➜  docker run &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$PWD&lt;/span&gt;:/data mottaquikarim/pkglambdalayer:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On completion, expect the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-ahl&lt;/span&gt;
total 1792
drwxr-xr-x   5 tkarim  staff   160B Dec 21 08:36 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxr-xr-x  23 tkarim  staff   736B Dec 21 08:31 ..
drwxr-xr-x  13 tkarim  staff   416B Dec 21 08:36 pkg
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;   1 tkarim  staff   879K Dec 21 08:36 pkg.zip
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt;   1 tkarim  staff    17B Dec 21 08:36 requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;pkg.zip&lt;/strong&gt; can be uploaded into your own Lambda Layer using the AWS Console 👍👍&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Backstory&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I teach a course at Baruch University where I introduce folks to various AWS technologies in the context of "Big Data" processing.&lt;/p&gt;

&lt;p&gt;So of course, Lambdas are a topic I cover. In order to keep the course load from being &lt;em&gt;too&lt;/em&gt; technical, I try to lean hard on AWS console whenever possible vs going too deeply into the infra-as-code  approach.&lt;/p&gt;

&lt;p&gt;As such, most of our explorations in Lambda-land are done through the AWS Lambda UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Problem&lt;/strong&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;You can't &lt;em&gt;actually&lt;/em&gt; load in dependencies into the AWS Lambda UI!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While I totally understand perhaps &lt;em&gt;why&lt;/em&gt; this is so, it definitely throws a bit of a curveball in my class as I want folks to write useful lambda funcs but without having to delve too deeply into the packaging process.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Lambda Layers and Docker&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I found Lambda Layers to be an acceptable compromise - last semester I just generated a single artifact similar to above which I shared via Google Drive and had folks go through the motions of uploading and leveraging the dependencies. &lt;/p&gt;

&lt;p&gt;This process seemed to be a good candidate for automation so as a first step, I packaged it into a docker image. Folks in my class have basic working knowledge of pulling / running docker images so next semester I hope to leverage this without having to pre-gen a single build artifact on my own.&lt;/p&gt;

&lt;p&gt;Plus, this will empower folks in class to perhaps do more with lambda if it is easier to create various combinations of dependencies in thier layers.&lt;/p&gt;

&lt;p&gt;I figured maybe this would be interesting/useful to others so I wrapped into a &lt;a href="https://github.com/mottaquikarim/pkglambdalayer"&gt;Github repo&lt;/a&gt; and am publishing/sharing. &lt;/p&gt;

</description>
      <category>docker</category>
      <category>serverless</category>
      <category>python</category>
    </item>
    <item>
      <title>Safely Construct Elasticsearch Queries w/Golang</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Wed, 16 Dec 2020 14:28:28 +0000</pubDate>
      <link>https://forem.com/taqkarim/safely-construct-elasticsearch-queries-w-golang-4ff3</link>
      <guid>https://forem.com/taqkarim/safely-construct-elasticsearch-queries-w-golang-4ff3</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL; DR&lt;/strong&gt;: ya boy wrote a golang elasticsearch query dsl utility. &lt;a href="https://github.com/mottaquikarim/esquerydsl"&gt;Find it here!&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;The Why&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you've used elasticsearch with golang, then you've probably used the &lt;a href="https://github.com/elastic/go-elasticsearch"&gt;official elasticsearch go client&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The es go client is exhaustive and generally, pretty great. However, it can be a bit...scary when having to deal with constructing search queries using the &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/7.10/query-dsl.html"&gt;elasticsearch query dsl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take for instance the following (from &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html#query-filter-context-ex"&gt;here&lt;/a&gt; in the docs):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/_search&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="nl"&gt;"bool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="nl"&gt;"must"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="s2"&gt;"Search"&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Elasticsearch"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"filter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; 
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"term"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"published"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"range"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"publish_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"gte"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-01-01"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Using strings&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;In my experience, the simplest/fastest way to construct this json string is with...well, a string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;elasticQuery&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;`
{
  "query": { 
    "bool": { 
      "must": [
        { "match": { "title":   "Search"        }},
        { "match": { "content": "Elasticsearch" }}
      ],
      "filter": [ 
        { "term":  { "status": "published" }},
        { "range": { "publish_date": { "gte": "2015-01-01" }}}
      ]
    }
  }
}
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we need to inject variable values, we just use &lt;code&gt;fmt.Sprintf&lt;/code&gt; and move on with our lives. The primary issue here is that validating/formatting these json strings require additional work and can be error prone (ie: fat-fingering an additional comma somewhere, etc).&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Using (use-case specific) structs&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;other&lt;/em&gt; approach would be to make everything hyper specific and create structs / custom marshal-ers that would generate the query DSL json format when &lt;code&gt;json.Marshal&lt;/code&gt; is called (on said custom struct(s)). &lt;/p&gt;

&lt;p&gt;This approach requires creating custom structs and code for the sole purpose of building these queries. (This may work for certain usecases! But, it also means more code and therefore additional maintenance and more trouble translating to other projects).&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;What does Google say?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The best "documentation"/support I could find through google-fu was &lt;a href="https://kb.objectrocket.com/elasticsearch/how-to-construct-elasticsearch-queries-from-a-string-using-golang-550"&gt;this article&lt;/a&gt; that also just suggested building a json string and crossing your fingers.&lt;/p&gt;

&lt;p&gt;(excerpt from the blog post above):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;constructQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c"&gt;// Build a query string from string passed to function&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;`{"query": {`&lt;/span&gt;

    &lt;span class="c"&gt;// Concatenate query string with string passed to method call&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;

    &lt;span class="c"&gt;// Use the strconv.Itoa() method to convert int to string&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;`}, "size": `&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;`}`&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;query:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Check for JSON errors&lt;/span&gt;
    &lt;span class="n"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Valid&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// returns bool&lt;/span&gt;

    &lt;span class="c"&gt;// Default query is "{}" if JSON is invalid&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"constructQuery() ERROR: query string not valid:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Using default match_all query"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{}"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"constructQuery() valid JSON:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Build a new string from JSON query&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Instantiate a *strings.Reader object from string&lt;/span&gt;
    &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="c"&gt;// Return a *strings.Reader object&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, there was &lt;a href="https://github.com/elastic/go-elasticsearch/issues/42"&gt;this issue&lt;/a&gt; on the go elasticsearch client from 2019:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This package is intentionally a low-level client, while olivere/elastic is a high-level client with extensions for building the requests and deserializing the responses. We are aiming for offering a more high-level API in the future, but — as I've indicated in other tickets — no sooner than a machine-readable, formal specification of the request and response bodies is available.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Moreover (and awesomely, that comment thread has a gem of a code snippet):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// BoolQuery Elastic bool query&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;BoolQuery&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Bool&lt;/span&gt; &lt;span class="n"&gt;BoolQueryParams&lt;/span&gt; &lt;span class="s"&gt;`json:"bool"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// BoolQueryParams params for an Elastic bool query&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;BoolQueryParams&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Must&lt;/span&gt;               &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="s"&gt;`json:"must,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;Should&lt;/span&gt;             &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="s"&gt;`json:"should,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;Filter&lt;/span&gt;             &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="s"&gt;`json:"filter,omitempty"`&lt;/span&gt;
    &lt;span class="n"&gt;MinimumShouldMatch&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;         &lt;span class="s"&gt;`json:"minimum_should_match,omitempty"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that looks very similar to what I've ended up with (wish I had seen this first, heh) as I tackled this problem.&lt;/p&gt;

&lt;p&gt;Regardless the main point is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Currently there isn't an easy way to define query DSL json strings for use with the elasticsearch go client.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And - for good reason perhaps - the official client looks like it will not support such a feature anytime soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;code&gt;package esquerydsl&lt;/code&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For all these reasons, I decided to build a simple, dependency less (aside from go stdlib deps) utility that generically defines structs to build queryDSL json strings.&lt;/p&gt;

&lt;p&gt;Here's an example (&lt;a href="https://play.golang.org/p/tlSkQH1mUGy"&gt;playground&lt;/a&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/mottaquikarim/esquerydsl"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;esquerydsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetQueryBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;esquerydsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryDoc&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"some_index"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Sort&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"asc"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
        &lt;span class="n"&gt;And&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;esquerydsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryItem&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;esquerydsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;QueryItem&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"some_index_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"some-long-key-id-value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"match"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"bool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"must"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"some_index_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"some-long-key-id-value"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"asc"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Find more examples in tests, including the initial queryDSL example referenced at the top of this post &lt;a href="https://github.com/mottaquikarim/esquerydsl/blob/master/esquerydsl_test.go#L26"&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;PRs welcome! Especially re: unittests such that documentation coverage is increased. If you use this lib and it is useful, do let me know please!&lt;/p&gt;

&lt;p&gt;Happy querying, fam 👍&lt;/p&gt;

</description>
      <category>elasticsearch</category>
      <category>go</category>
      <category>programming</category>
    </item>
    <item>
      <title>Gotcha w/comparing base64 encoded strs</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Sun, 13 Dec 2020 09:29:57 +0000</pubDate>
      <link>https://forem.com/taqkarim/gotcha-w-comparing-base64-encoded-strs-3b2k</link>
      <guid>https://forem.com/taqkarim/gotcha-w-comparing-base64-encoded-strs-3b2k</guid>
      <description>&lt;p&gt;Here's a fun experiment - consider two "numerical" strings such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1004"&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1053"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Is &lt;code&gt;a &amp;lt; b&lt;/code&gt;?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Why yes, of course it is!&lt;/p&gt;

&lt;p&gt;Ok, let's try this again, this time b64encoding our two strings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;base64&lt;/span&gt;

&lt;span class="n"&gt;a_b64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf8"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# MTAwNA==
&lt;/span&gt;&lt;span class="n"&gt;b_b64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf8"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# MTA1Mw==
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How about now? &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Is &lt;code&gt;a_b64 &amp;lt; b_b64&lt;/code&gt;?&lt;/strong&gt;
&lt;/h3&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;NOPE.&lt;/strong&gt;
&lt;/h1&gt;




&lt;p&gt;What gives?! &lt;/p&gt;

&lt;p&gt;And more importantly, this observation implies that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given two strings a, b such that &lt;code&gt;a &amp;lt; b&lt;/code&gt; it is &lt;strong&gt;not necessarily true&lt;/strong&gt; that &lt;code&gt;b64(a) &amp;lt; b64(b)&lt;/code&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;(This is the key takeaway, the rest of this post explains why this is true for some cases)&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;But why though?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To answer this question, we must delve into the b64 encoding algorithm itself. Let's consider &lt;code&gt;1004&lt;/code&gt; as an example.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1:&lt;/strong&gt; split the string by digit
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;1004&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2:&lt;/strong&gt; convert each char to binary equivalent in &lt;a href="https://www.rapidtables.com/code/text/ascii-table.html"&gt;ASCII&lt;/a&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;1004&lt;/th&gt;
&lt;th&gt;ASCII value&lt;/th&gt;
&lt;th&gt;Binary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;td&gt;00110001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;00110000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;00110000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;00110100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3:&lt;/strong&gt; concatenate the binary representation
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;1004&lt;/code&gt; =&amp;gt; &lt;code&gt;00110001001100000011000000110100&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4:&lt;/strong&gt; partition the above but now in groups &lt;code&gt;6&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;1004 (in groups of 6)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;001100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;010011&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;000000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;110000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;001101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00*&lt;em&gt;0000&lt;/em&gt;* (pad 4 to complete final group&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5:&lt;/strong&gt; pad-left each partition to convert our 6 bit "byte" into an 8 bit byte
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;1004&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;00001100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00010011&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00000000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00110000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00001101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00000000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 6:&lt;/strong&gt; convert back to decimal (base 10) and translate by looking up each decimal value in the &lt;a href="https://base64.guru/learn/base64-characters"&gt;base64 characters table&lt;/a&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;1004&lt;/th&gt;
&lt;th&gt;decimal&lt;/th&gt;
&lt;th&gt;b64 character&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;00001100&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00010011&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;T&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00000000&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00110000&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;w&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00001101&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;00000000&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;So, &lt;code&gt;1004&lt;/code&gt; =&amp;gt; &lt;code&gt;MTAwNA&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tada!&lt;/p&gt;

&lt;p&gt;Now (&lt;em&gt;do&lt;/em&gt; try this at home, if you want): repeat this exercise for &lt;code&gt;1053&lt;/code&gt;, resulting in:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;1053&lt;/code&gt; =&amp;gt; &lt;code&gt;MTA1Mw&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note that &lt;code&gt;MTAwNA&lt;/code&gt; &lt;strong&gt;&amp;gt;&lt;/strong&gt; &lt;code&gt;MTA1Mw&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The key to understanding why &lt;code&gt;b64(a) !&amp;lt; b64(b)&lt;/code&gt; has to do with &lt;strong&gt;Step 6&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;We convert our new, transformed decimal values according to the base64 characters table - which places numbers such as &lt;code&gt;1-9&lt;/code&gt; as &lt;em&gt;higher&lt;/em&gt; than characters (in terms of index value).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7lKaDoOJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w9bi3we0hlb75gbgq3cy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7lKaDoOJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/w9bi3we0hlb75gbgq3cy.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how &lt;code&gt;1&lt;/code&gt; has decimal value &lt;code&gt;53&lt;/code&gt; and &lt;code&gt;w&lt;/code&gt; has decimal value &lt;code&gt;48&lt;/code&gt;. Contrast this to the ASCII table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8cjvBWUf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zln3xr8oy13i5ysguoqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8cjvBWUf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zln3xr8oy13i5ysguoqg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;"1"&lt;/code&gt; has a decimal value of &lt;strong&gt;49&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wKTbman0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/44cwso2s9neqzvpejp3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wKTbman0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/44cwso2s9neqzvpejp3e.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;"w"&lt;/code&gt; has a decimal value of &lt;strong&gt;77&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;So, when comparing &lt;code&gt;"w" &amp;gt; "1"&lt;/code&gt; as strings, the expression is evaluated as &lt;code&gt;True&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;In other words, when we convert our bits from &lt;strong&gt;Step 4&lt;/strong&gt; to characters, we splice the binary representation because our total # of bits is not divisible by 6 (see my &lt;strong&gt;PPS&lt;/strong&gt; for more info). &lt;/p&gt;

&lt;p&gt;Then we convert this spliced value in our b64 table where the numeric chars (1-9) have indices that are &lt;em&gt;higher&lt;/em&gt; than the indices of the non-numeric chars (A-Z and a-z). &lt;/p&gt;

&lt;p&gt;For this reason, when we attempt to perform a string compare, &lt;code&gt;1004&lt;/code&gt; in b64 encoded form (&lt;code&gt;MTAwNA&lt;/code&gt;) is indeed less than &lt;code&gt;1053&lt;/code&gt; in b64 encoded form (&lt;code&gt;MTA1Mw&lt;/code&gt;) according to the rules of b64 translation but &lt;strong&gt;not according to the ASCII translation&lt;/strong&gt; (see my &lt;strong&gt;PS&lt;/strong&gt; for more info). &lt;/p&gt;

&lt;p&gt;In ASCII format, &lt;code&gt;MTAwNA&lt;/code&gt; is indeed "greater" than &lt;code&gt;MTA1Mw&lt;/code&gt; since char position 3 in &lt;code&gt;MTAwNA&lt;/code&gt; (&lt;code&gt;w&lt;/code&gt;) actually has a numerical index that is higher than char position 3 in &lt;code&gt;MTA1Mw&lt;/code&gt; (&lt;code&gt;1&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Womp womp.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Ok but...why care about this?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Well, long story short: friends don't let friends take fields in their elasticsearch index, b64 encode them into a key and then run queries sorting by these keys because well...it won't work. &lt;/p&gt;

&lt;p&gt;I had one hell of a time figuring this out and even when I observed it, I had trouble justifying this to myself hence this post (which I used to work out my feelings on the matter).&lt;/p&gt;

&lt;p&gt;I feel slightly better now.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;: in py3 we compare unicode values not ascii when performing string comparison ops - but for the purposes of this post the &lt;a href="https://www.ssec.wisc.edu/~tomw/java/unicode.html"&gt;decimal values are the same&lt;/a&gt; since we are only contending with &lt;code&gt;A-Z, a-z,0-9,+,/&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;PPS&lt;/strong&gt;: 8N mod 6 will always have remainder 2, 4, or 0. This problem seems to show up specifically when (8N mod 6) == 2 (ie: we pad 4 0s to the right of our last row). The mod 0 case is obvious but I've yet to explain why (8N mod 6) == 4 does not seem to this problem.&lt;/p&gt;

</description>
      <category>python</category>
      <category>elasticsearch</category>
      <category>programming</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Extending SimpleNamespace for Nested Dictionaries</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Mon, 13 Apr 2020 08:35:33 +0000</pubDate>
      <link>https://forem.com/taqkarim/extending-simplenamespace-for-nested-dictionaries-58e8</link>
      <guid>https://forem.com/taqkarim/extending-simplenamespace-for-nested-dictionaries-58e8</guid>
      <description>&lt;p&gt;I'm a huge fan of Python3's &lt;code&gt;types.SimpleNamespace&lt;/code&gt;. Basically, it allows us to take a dict, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;my_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;my_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 1
&lt;/span&gt;&lt;span class="n"&gt;my_dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# 2, etc
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and manage it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SimpleNamespace&lt;/span&gt;
&lt;span class="n"&gt;my_namespace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SimpleNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;my_namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="c1"&gt;# 1
&lt;/span&gt;&lt;span class="n"&gt;my_namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="c1"&gt;# 2
&lt;/span&gt;&lt;span class="n"&gt;my_namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="c1"&gt;# 3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Alternatively, we could also do something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SimpleNamespace&lt;/span&gt;

&lt;span class="n"&gt;my_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;my_namespace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SimpleNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;my_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;my_namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="c1"&gt;# 1
&lt;/span&gt;&lt;span class="n"&gt;my_namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="c1"&gt;# 2
&lt;/span&gt;&lt;span class="n"&gt;my_namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="c1"&gt;# 3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But - what happens if our &lt;code&gt;my_dict&lt;/code&gt; is nested? Like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;my_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="s"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"e"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,{&lt;/span&gt;
    &lt;span class="s"&gt;"f"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;my_namespace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SimpleNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;my_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;my_namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="c1"&gt;# {"d": 4} /womp womp 😭
&lt;/span&gt;&lt;span class="n"&gt;my_namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="c1"&gt;# raises Exception! 😭😭
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In short, &lt;code&gt;SimpleNamespace&lt;/code&gt; simply does not support this use case. But that's ok! We can extend &lt;code&gt;SimpleNamespace&lt;/code&gt; and build this functionality for ourselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining &lt;code&gt;RecursiveNamespace&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SimpleNamespace&lt;/span&gt;

&lt;span class="c1"&gt;# this is how SimpleNamespace looks when output
&lt;/span&gt;&lt;span class="n"&gt;SimpleNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;my_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# namespace(a={'d': 4}, b=2, c=3, e=[5, 6, 7, {'f': 8}])
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecursiveNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SimpleNamespace&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

  &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;staticmethod&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;map_entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;RecursiveNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RecursiveNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="c1"&gt;# this is how RecursiveNamespace looks when output
&lt;/span&gt;&lt;span class="n"&gt;RecursiveNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;my_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# RecursiveNamespace(
#    a=RecursiveNamespace(d=4), 
#    b=2, 
#    c=3, 
#    e=[5, 6, 7, RecursiveNamespace(f=8)])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So, what's happening here? We establish a new class, &lt;code&gt;RecursiveNamespace&lt;/code&gt; that extends &lt;code&gt;SimpleNamespace&lt;/code&gt;. In the &lt;code&gt;__init__&lt;/code&gt; constructor method, we call &lt;code&gt;SimpleNamespace&lt;/code&gt;'s constructor. Then, we just walk through our dictionary and for value that is &lt;em&gt;also&lt;/em&gt; a dictionary or list, we instantiate that with &lt;code&gt;RecursiveNamespace&lt;/code&gt;. Ta da.&lt;/p&gt;

&lt;h2&gt;
  
  
  P.S.
&lt;/h2&gt;

&lt;p&gt;Technically, we don't even really need &lt;code&gt;types.SimpleNamespace&lt;/code&gt; here - we can implement this class without by just adding two lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecursiveNamespace2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# without extending SimpleNamespace!
&lt;/span&gt;
  &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;staticmethod&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;map_entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;RecursiveNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RecursiveNamespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map_entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# this is the only addition
&lt;/span&gt;        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Self-grading quizzes with Airtable</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Mon, 16 Mar 2020 13:37:13 +0000</pubDate>
      <link>https://forem.com/taqkarim/self-grading-quizzes-with-airtable-3o5j</link>
      <guid>https://forem.com/taqkarim/self-grading-quizzes-with-airtable-3o5j</guid>
      <description>&lt;p&gt;This semester, I am teaching a course at Baruch University on Big Data Technologies. &lt;/p&gt;

&lt;p&gt;I resolved to administer a small quiz at the start of class to get a feel for how the class is doing overall in terms of comprehension of key materials. &lt;/p&gt;

&lt;p&gt;However, grading quizzes - especially at such a recurring cadence - will definitely be time consuming, even for a small class of say 15 people (my class has 47 students).&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;I wanted a system that would:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make it easy to create multi-question, &lt;em&gt;multiple choice&lt;/em&gt; quizzes&lt;/li&gt;
&lt;li&gt;Make grading automatic&lt;/li&gt;
&lt;li&gt;Share individual grades automatically to students via email or some other manner&lt;/li&gt;
&lt;li&gt;Require minimal infrastructure and coding (ie: maybe a lambda function somewhere? ideally no code at all)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  TL;DR:
&lt;/h2&gt;

&lt;p&gt;Using Airtable, there is a way to create multi-choice, self grading quizzes. I've created a set up that you can &lt;strong&gt;find and replicate&lt;/strong&gt; here for your class's usecase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://airtable.com/shriZOQyCUScx3zCc"&gt;AIRTABLE BASE&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://airtable.com/shr2hBhcm33iRV5jK"&gt;QUIZ FORM&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Airtable based solution
&lt;/h2&gt;

&lt;p&gt;Leveraging &lt;a href="https://airtable.com/"&gt;Airtable&lt;/a&gt;, I have come up with an approach that generally has worked for me thus far.&lt;/p&gt;

&lt;p&gt;The key to this solution is to create a table that represents a quiz. Each row will include student name, email, created time, "questions", "checks" and a "grade".&lt;/p&gt;

&lt;p&gt;The last two types of rows: "checks" and "grade" are both formula types.&lt;/p&gt;

&lt;p&gt;Here's a screenshot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9bWn14nG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0i10457qg9scp4dj756k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9bWn14nG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0i10457qg9scp4dj756k.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The columns "1"..."5" represent questions and each are formatted to be "single select" types with 4 predefined selections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Formula Columns
&lt;/h3&gt;

&lt;p&gt;To assert correctness, each "question" column has an accompanying "solution" column that asserts for correctness. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YiSCCgIQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8nopme8drybkye5vibnq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YiSCCgIQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/8nopme8drybkye5vibnq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As seen here, "Solution 1" is a formula &lt;code&gt;{1} = "C"&lt;/code&gt; which is ensuring that the selection for column "1", if "C" is correct. This can be repeated with as many questions as necessary.&lt;/p&gt;

&lt;p&gt;To compute grade, we simply find the average:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WLnd39Wf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hynfw25jjyci1swotdy5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WLnd39Wf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hynfw25jjyci1swotdy5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The "code" for this formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;({Solution 1} + {Solution 2} + {Solution 3} + {Solution 4} + {Solution 5})/5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where the label inside each &lt;code&gt;{}&lt;/code&gt; corresponds to the column name &lt;code&gt;Solution 1&lt;/code&gt;...&lt;code&gt;Solution 5&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's it! That's the internals of the quiz. Now, per student who completes this quiz, a corresponding row will be created with a "creation time" (for future filtering if needed) and "checks" for each question submitted and a "grade" that computes average.&lt;/p&gt;

&lt;p&gt;If needed that "grade" column can also be updated to weight individual questions differently as well. 👍&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the quiz
&lt;/h2&gt;

&lt;p&gt;For the "frontend", we need a form and the actual quiz questions! Airtable supports a concept of a "view" where it is possible to create a "form" that will populate the rows in the table.&lt;/p&gt;

&lt;p&gt;Here's an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5mF26X5g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mbazzoh4y7bdcja75epp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5mF26X5g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mbazzoh4y7bdcja75epp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essentially, each column from the table can be added (or removed!) as an input field. Also, it is possible to make certain fields required and to add arbitrary text (in my quiz, I even had a few coding questions). &lt;/p&gt;

&lt;p&gt;Additionally, this form is by default not shared:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zvFb-yJi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aqczrffb7hkpr7q3yvfk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zvFb-yJi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aqczrffb7hkpr7q3yvfk.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;but can be toggled to shareable via a private link at any time (so it is easy to "publish" and "unpublish" a quiz)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3KR4c8as--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9mwb6oin87i21ol8jcxp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3KR4c8as--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9mwb6oin87i21ol8jcxp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Verdict
&lt;/h2&gt;

&lt;p&gt;For a non-custom coded system, this works "well enough"; looking back to the requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅Make it easy to create multi-question, &lt;em&gt;multiple choice&lt;/em&gt; quizzes&lt;/li&gt;
&lt;li&gt;✅Make grading automatic&lt;/li&gt;
&lt;li&gt;❌Share individual grades automatically to students via email or some other manner&lt;/li&gt;
&lt;li&gt;✅Require minimal infrastructure and coding (ie: maybe a lambda function somewhere? ideally no code at all)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some happy additional features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅Tables and views are easy to duplicate, meaning multiple quizzes can be easily supported&lt;/li&gt;
&lt;li&gt;✅Publishing/unpublishing forms are actually super helpful&lt;/li&gt;
&lt;li&gt;✅At the bottom of each column, airtable calculates some metrics such as class average, etc which can be read in real time as students complete quiz&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Sfykps8K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f7eu9t5borc7108f243x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Sfykps8K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f7eu9t5borc7108f243x.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are some definite drawbacks here as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌lack of fine tuned controls in terms of formatting the questions &lt;/li&gt;
&lt;li&gt;❌adding more than 4-5 questions becomes somewhat unreasonable due to the additional column that much be added&lt;/li&gt;
&lt;li&gt;❌&lt;strong&gt;RATE LIMITS&lt;/strong&gt;! If more that ~50 people open the form all at once (or refresh a lot), I've seen cases where the form is "disabled momentarily" (a few hours)&lt;/li&gt;
&lt;li&gt;❌no automatic support for emailing grades to students&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For that last item - I have come up with a (similarly codeless) solution! If there is sufficient interest (please let me know in the comments!) I will follow up this post with a tutorial for how I achieved near-real time email notification to students based on quiz submission 👍&lt;/p&gt;

</description>
      <category>learning</category>
      <category>tutorial</category>
      <category>serverless</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Connecting to ElasticSearch configured via Docker</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Mon, 16 Mar 2020 05:39:13 +0000</pubDate>
      <link>https://forem.com/taqkarim/connecting-to-elasticsearch-configured-via-docker-4ngn</link>
      <guid>https://forem.com/taqkarim/connecting-to-elasticsearch-configured-via-docker-4ngn</guid>
      <description>&lt;h1&gt;
  
  
  Elastic Search and Docker
&lt;/h1&gt;

&lt;p&gt;Setting up an elasticsearch + kibana runtime is very easy to do with docker-compose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;elasticsearch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.elastic.co/elasticsearch/elasticsearch:6.3.2&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cluster.name=docker-cluster&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;bootstrap.memory_lock=true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ES_JAVA_OPTS=-Xms512m&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-Xmx512m"&lt;/span&gt;
    &lt;span class="na"&gt;ulimits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;memlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;soft&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-1&lt;/span&gt;
        &lt;span class="na"&gt;hard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;-1&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9200:9200"&lt;/span&gt;
  &lt;span class="na"&gt;kibana&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker.elastic.co/kibana/kibana:6.3.2&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5601:5601"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For more information on the defaults (&lt;code&gt;ulimits&lt;/code&gt; or &lt;code&gt;environment&lt;/code&gt; variables, please see &lt;a href="https://blog.k2datascience.com/running-elasticsearch-kibana-using-docker-5ff10ad017d0"&gt;this&lt;/a&gt; post)&lt;/p&gt;

&lt;p&gt;To run, you simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And then navigate over to &lt;a href="http://localhost:9200"&gt;http://localhost:9200&lt;/a&gt; for elasticsearch or &lt;a href="http://localhost:5601"&gt;http://localhost:5601&lt;/a&gt; for kibana.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas
&lt;/h2&gt;

&lt;p&gt;As with all things, there may be some gotchas associated with this setup. Specifically, you may notice that sometimes navigating to the URLs referenced above will result in connection errors.&lt;/p&gt;

&lt;p&gt;This can be for quite a few reasons, I'll list some common ones I've encountered below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows: ElasticSearch doesn't work
&lt;/h3&gt;

&lt;p&gt;A few things to check - run a &lt;code&gt;docker ps -a&lt;/code&gt; to ensure your container is running and for how long.&lt;/p&gt;

&lt;p&gt;if it only lives for a few seconds, it may be due to a default &lt;a href="https://stackoverflow.com/a/11685165"&gt;&lt;code&gt;max_map_count&lt;/code&gt; issue&lt;/a&gt;. To fix, if using &lt;code&gt;docker-machine&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-machine ssh
&lt;span class="nb"&gt;sudo &lt;/span&gt;sysctl &lt;span class="nt"&gt;-w&lt;/span&gt; vm.max_map_count&lt;span class="o"&gt;=&lt;/span&gt;262144
&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If &lt;em&gt;not&lt;/em&gt; using &lt;code&gt;docker-machine&lt;/code&gt;, try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;container_id&amp;gt; /bin/bash
sysctl &lt;span class="nt"&gt;-w&lt;/span&gt; vm.max_map_count&lt;span class="o"&gt;=&lt;/span&gt;262144
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;NOTE&lt;/em&gt;: this will not persist after container is killed. TO make it "permanent" you might want to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;vi /etc/sysctl.conf
vm.max_map_count&lt;span class="o"&gt;=&lt;/span&gt;262144
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(press &lt;code&gt;:q&lt;/code&gt; to exit)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;vi /etc/rc.local
&lt;span class="nb"&gt;echo &lt;/span&gt;262144 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /proc/sys/vm/max_map_count
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://stackoverflow.com/a/53047291"&gt;&lt;em&gt;source&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Even after changes above, not working
&lt;/h3&gt;

&lt;p&gt;One bit to note is that the docker container is simply wrapping the elasticsearch service. As such, sometimes it just takes a bit of time to load.&lt;/p&gt;

&lt;p&gt;To ensure that elasticsearch is running properly, consider running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose logs elasticsearch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will display the log messages emitted as elasticsearch is booted inside your container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;example_elasticsearch | &lt;span class="o"&gt;[&lt;/span&gt;2020-03-16T05:32:12,704][INFO &lt;span class="o"&gt;][&lt;/span&gt;o.e.n.Node               &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;IzFG4tZ] initialized
example_elasticsearch | &lt;span class="o"&gt;[&lt;/span&gt;2020-03-16T05:32:12,704][INFO &lt;span class="o"&gt;][&lt;/span&gt;o.e.n.Node               &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;IzFG4tZ] starting ...
example_elasticsearch | &lt;span class="o"&gt;[&lt;/span&gt;2020-03-16T05:32:12,959][INFO &lt;span class="o"&gt;][&lt;/span&gt;o.e.t.TransportService   &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;IzFG4tZ] publish_address &lt;span class="o"&gt;{&lt;/span&gt;172.18.0.2:9300&lt;span class="o"&gt;}&lt;/span&gt;, bound_addresses &lt;span class="o"&gt;{&lt;/span&gt;0.0.0.0:9300&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you see those three lines, you &lt;em&gt;should&lt;/em&gt; be safe to attempt your "healthcheck" such as visiting &lt;code&gt;http://localhost:9200&lt;/code&gt; in the browser or curling for it.&lt;/p&gt;

&lt;p&gt;Alternatively, if something is foobar'd you'll see it here which gives you further clues as to what went wrong.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>windows</category>
    </item>
    <item>
      <title>PyTennessee 2020: Lessons Learned After a Year of Serverless in Production</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Wed, 11 Mar 2020 15:42:14 +0000</pubDate>
      <link>https://forem.com/taqkarim/pytennessee-2020-lessons-learned-after-a-year-of-serverless-in-production-1cjg</link>
      <guid>https://forem.com/taqkarim/pytennessee-2020-lessons-learned-after-a-year-of-serverless-in-production-1cjg</guid>
      <description>&lt;p&gt;It was great speaking at PyTennessee 2020 this year, kicking off the first of 4 scheduled talks I have in Q2 around "serverless" technologies.&lt;/p&gt;


&lt;div class="ltag_speakerdeck"&gt;
  &lt;iframe height="463" id="talk_frame_0ebf85a4a0c441d98a33907bdcf5b155" src="//speakerdeck.com/player/0ebf85a4a0c441d98a33907bdcf5b155" width="710"&gt;&lt;/iframe&gt;
&lt;/div&gt;


</description>
      <category>python</category>
      <category>serverless</category>
      <category>aws</category>
      <category>techtalks</category>
    </item>
    <item>
      <title>Docker, Code Coverage and Jenkins</title>
      <dc:creator>Taq Karim</dc:creator>
      <pubDate>Wed, 11 Mar 2020 15:30:04 +0000</pubDate>
      <link>https://forem.com/taqkarim/docker-code-coverage-and-jenkins-n7</link>
      <guid>https://forem.com/taqkarim/docker-code-coverage-and-jenkins-n7</guid>
      <description>&lt;p&gt;&lt;em&gt;These posts are super quick and to the point - mainly, they are solutions that worked for me but were not anything I could easily find googling.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Trying to write to &lt;code&gt;.coverage&lt;/code&gt; inside of docker fails. Here's the dump:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INTERNALERROR&amp;gt; Traceback (most recent call last):
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/_pytest/main.py", line 206, in wrap_session
INTERNALERROR&amp;gt;     session.exitstatus = doit(config, session) or 0
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/_pytest/main.py", line 250, in _main
INTERNALERROR&amp;gt;     config.hook.pytest_runtestloop(session=session)
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR&amp;gt;     return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR&amp;gt;     return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/pluggy/manager.py", line 87, in &amp;lt;lambda&amp;gt;
INTERNALERROR&amp;gt;     firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/pluggy/callers.py", line 203, in _multicall
INTERNALERROR&amp;gt;     gen.send(outcome)
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/pytest_cov/plugin.py", line 254, in pytest_runtestloop
INTERNALERROR&amp;gt;     self.cov_controller.finish()
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/pytest_cov/engine.py", line 197, in finish
INTERNALERROR&amp;gt;     self.cov.stop()
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/coverage/control.py", line 782, in save
INTERNALERROR&amp;gt;     self.data_files.write(self.data, suffix=self.data_suffix)
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/coverage/data.py", line 680, in write
INTERNALERROR&amp;gt;     data.write_file(filename)
INTERNALERROR&amp;gt;   File "/usr/local/lib/python2.7/site-packages/coverage/data.py", line 467, in write_file
INTERNALERROR&amp;gt;     with open(filename, 'w') as fdata:
INTERNALERROR&amp;gt; IOError: [Errno 13] Permission denied: '/app/.coverage'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Woof. The issue is definitely due to permissions issues. Here's my docker command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -v $(PWD):/app some_image pytest --cov=some_dir
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;Adding &lt;code&gt;--user=root&lt;/code&gt; solved my problem&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --user=root -v $(PWD):/app some_image pytest --cov=some_dir
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case, as I am simply running some unit tests I don't think running as root user makes much of a difference. (Also note that if you are using docker-compose, there is also a supported method for specifying user either via cmd line or in docker-compose file)&lt;/p&gt;

&lt;p&gt;I hope this helps! &lt;/p&gt;

</description>
      <category>docker</category>
      <category>python</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
