<?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: Boston Cartwright</title>
    <description>The latest articles on Forem by Boston Cartwright (@bstncartwright).</description>
    <link>https://forem.com/bstncartwright</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%2F154652%2Fdd75e204-d79d-46d1-9675-b124ba5a9ee7.jpeg</url>
      <title>Forem: Boston Cartwright</title>
      <link>https://forem.com/bstncartwright</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bstncartwright"/>
    <language>en</language>
    <item>
      <title>Handling errors concurrently in Go with ErrGroup</title>
      <dc:creator>Boston Cartwright</dc:creator>
      <pubDate>Mon, 13 Sep 2021 19:09:21 +0000</pubDate>
      <link>https://forem.com/bstncartwright/handling-errors-concurrently-in-go-with-errgroup-i8</link>
      <guid>https://forem.com/bstncartwright/handling-errors-concurrently-in-go-with-errgroup-i8</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://golang.org/doc/effective_go#concurrency"&gt;Concurrency&lt;/a&gt; is one of Go's strong points and I love working with the paradigm that the Go team has built.&lt;/p&gt;

&lt;p&gt;It is a big topic with lots to talk about. I recommend reading through the &lt;a href="https://golang.org/doc/effective_go#concurrency"&gt;Effective Go documentation&lt;/a&gt; about concurrency in Go to learn about goroutines, channels, and how they all work together.&lt;/p&gt;

&lt;p&gt;Error handling is also done differently in Go than other languages, thanks to &lt;a href="https://golang.org/doc/effective_go#multiple-returns"&gt;multiple return values&lt;/a&gt;. I recommend reading their blog &lt;a href="https://blog.golang.org/error-handling-and-go"&gt;post on error handling&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  ErrGroup
&lt;/h2&gt;

&lt;p&gt;If you don't need to do any further work off of the errors, use an &lt;a href="https://pkg.go.dev/golang.org/x/sync/errgroup"&gt;ErrGroup&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;An ErrGroup is essentially a wrapped &lt;a href="https://pkg.go.dev/sync#WaitGroup"&gt;sync.WaitGroup&lt;/a&gt; to catch errors out of the started goroutines.&lt;/p&gt;

&lt;h3&gt;
  
  
  WaitGroup
&lt;/h3&gt;

&lt;p&gt;Here is an example without errors using a WaitGroup (from godoc):&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;"sync"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;httpPkg&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;httpPkg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&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;http&lt;/span&gt; &lt;span class="n"&gt;httpPkg&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="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="o"&gt;=&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;"http://www.golang.org/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"http://www.google.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"http://www.somename.com/"&lt;/span&gt;&lt;span class="p"&gt;,&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Increment the WaitGroup counter.&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;// Launch a goroutine to fetch the URL.&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// Decrement the counter when the goroutine completes.&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="c"&gt;// Fetch the URL.&lt;/span&gt;
            &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// Wait for all HTTP fetches to complete.&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&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;"Successfully fetched all URLs."&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;To use a WaitGroup, first create the group:&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;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, for every goroutine, add that number to the group:&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;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then whenever a goroutine is done, tell the group:&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;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The &lt;a href="https://tour.golang.org/flowcontrol/12"&gt;defer&lt;/a&gt; keyword:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It defers the execution of the statement following the keyword until the surrounding function returns.&lt;/p&gt;

&lt;p&gt;Read more about it in the &lt;a href="https://tour.golang.org/flowcontrol/12"&gt;tour of go&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, wait for the group to complete:&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;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, there are no errors that can occur. Let's look at how it changes if we needed to catch errors, using an ErrGroup.&lt;/p&gt;

&lt;h2&gt;
  
  
  ErrGroup
&lt;/h2&gt;

&lt;p&gt;Here is the same example as above but using an ErrGroup (from godoc):&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;"net/http"&lt;/span&gt;

    &lt;span class="s"&gt;"golang.org/x/sync/errgroup"&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;g&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errgroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Group&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;urls&lt;/span&gt; &lt;span class="o"&gt;=&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;"http://www.golang.org/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"http://www.google.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"http://www.somename.com/"&lt;/span&gt;&lt;span class="p"&gt;,&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Launch a goroutine to fetch the URL.&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="c"&gt;// https://golang.org/doc/faq#closures_and_goroutines&lt;/span&gt;
        &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// Fetch the URL.&lt;/span&gt;
            &lt;span class="n"&gt;resp&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&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;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;// Wait for all HTTP fetches to complete.&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;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&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="no"&gt;nil&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;"Successfully fetched all URLs."&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks very similar, here are the differences:&lt;/p&gt;

&lt;p&gt;First, create the group:&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;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

&lt;span class="c"&gt;// VVV BECOMES VVV&lt;/span&gt;

&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errgroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, instead of adding every goroutine to the group, call &lt;code&gt;g.Go&lt;/code&gt; with the function to be a goroutine. The only requirement is it must have the following signature: &lt;code&gt;func() error&lt;/code&gt;. Also, since the ErrGroup will handle when goroutines are completed, there is no need to call &lt;code&gt;wg.Done()&lt;/code&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;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// Decrement the counter when the goroutine completes.&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="c"&gt;// ... work that can return error here&lt;/span&gt;
&lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// VVV BECOMES VVV&lt;/span&gt;

&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// ... work that can return error here&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, wait for the group to finish and handle the errors as needed:&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;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// VVV BECOMES VVV&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;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&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="no"&gt;nil&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;"Successfully fetched all URLs."&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;ErrGroups provide lots of opportunities on handling errors in goroutines.&lt;/p&gt;

&lt;p&gt;That being said, ErrGroup is just another tool in the toolbox that should be used when the use case fits.&lt;br&gt;
If some more complex decisions and work needs to be made based off of the errors, a channel is probably better fit.&lt;/p&gt;

&lt;p&gt;What do you think? &lt;/p&gt;

</description>
      <category>go</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Fix bugs by reading the room</title>
      <dc:creator>Boston Cartwright</dc:creator>
      <pubDate>Tue, 16 Mar 2021 18:37:23 +0000</pubDate>
      <link>https://forem.com/bstncartwright/fix-bugs-by-reading-the-room-1pg6</link>
      <guid>https://forem.com/bstncartwright/fix-bugs-by-reading-the-room-1pg6</guid>
      <description>&lt;p&gt;In a previous project, my team and I were working hard to get ready for a&lt;br&gt;
release. This release was scheduled for the end of the week since our&lt;br&gt;
application was used in an enterprise setting and the weekend is when we&lt;br&gt;
would affect the least amount of users.&lt;/p&gt;

&lt;p&gt;We scheduled the deployment for Friday (&lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/f79iag/dont_deploy_on_fridays/"&gt;yes&lt;/a&gt;, &lt;a href="https://www.reddit.com/r/ProgrammerHumor/comments/aqxpcl/remember_dont_deploy_on_fridays/"&gt;I know this&lt;/a&gt; &lt;a href="https://twitter.com/cassidoo/status/1154809678607446016"&gt;is a bad idea&lt;/a&gt;),and were working towards it.&lt;/p&gt;

&lt;p&gt;On Thursday, I woke up sick. For my health, I didn't work and spent the day&lt;br&gt;
resting in bed. However for my team, a new critical bug had surfaced.&lt;/p&gt;

&lt;p&gt;In this application, we had what Kent calls a &lt;a href="https://epicreact.dev/soul-crushing-components/"&gt;&lt;strong&gt;Soul Crushing Component&lt;/strong&gt;&lt;/a&gt;. This component was complex, and had lots of different states it could be in.&lt;/p&gt;

&lt;p&gt;To make matters worse, features for this component were added over the course of a year, by many different developers. These developers didn't always follow the same state management pattern laid out at the beginning, so state was being managed in many different ways, including Redux, local storage, React Hooks, and more.&lt;/p&gt;

&lt;p&gt;It was the component you ran from.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3o7ZesoD2nZikdXEAM/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3o7ZesoD2nZikdXEAM/giphy.gif" alt="muppet running away"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And thus, the bug was in this component. In essence, if you followed a specific flow of steps, this component would get put in an &lt;a href="https://kentcdodds.com/blog/make%20impossible-states-impossible"&gt;impossible state&lt;/a&gt;, and get stuck appearing that it is loading.&lt;/p&gt;

&lt;p&gt;This was marked as a show stopper for the production deployment, and my team quickly tried to find a solution.&lt;/p&gt;

&lt;p&gt;I was sick the day this surfaced, and do not know the details of all the attempts to solve it that day.&lt;/p&gt;

&lt;p&gt;However, when I came into work the next day it seems we were still working on this bug. I joined a war room talking about it, and was quickly caught up on the details that have been found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You get stuck in an impossible state: Data has been returned from our API but component still shows loading.&lt;/li&gt;
&lt;li&gt;It only happens when you follow a specific path (~5% of users would run into this)&lt;/li&gt;
&lt;li&gt;As a workaround, you can refresh the page and it works again (which was unacceptable to the client)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There already was a small team of developers who were attempting to fix this. They were trying to find how the impossible state existed and how they could actually deem it impossible. After spending many hours the day before, they had no success but had come up with a design document on how state is managed in this component.&lt;/p&gt;

&lt;p&gt;I recognized in this war room that this was putting the deploy in jeopardy, which would be bad for everyone involved. Seeing the work that had already been done, I started thinking of alternate solutions. We needed a fast solution in order to make deployment in time.&lt;/p&gt;

&lt;p&gt;I didn't want to work a lot on refactoring the state management issues because we did not have enough time to fix them. Taking that approach would most likely equal the whole team working the weekend when a new bug was found in production due to our quick changes.&lt;/p&gt;

&lt;p&gt;I realized one thing that was found:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a workaround, you can refresh the page and it works again&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And thus I forced a refresh anytime you followed this path. Now this wasn't super pretty, and was a little jarring for the user for about a second. But this solution was a sure-fire fix that would not cause more issues once deployed.&lt;/p&gt;

&lt;p&gt;I was able to write this fix within minutes, had a PR open, and we were on schedule to deploy by lunch time.&lt;/p&gt;

&lt;p&gt;Reflecting on this, I learned a lesson that I can apply to many more situations in the future: &lt;strong&gt;Read the room&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I understood the importance of this deployment, how many users were affected by it, and the possibility of a &lt;em&gt;correct&lt;/em&gt; fix causing more issues due to time pressure.&lt;/p&gt;

&lt;p&gt;By doing my simple quick fix, we were able to dedicate more time into refactoring the entire state management for this component for the next release. We took our time, and the result ended up being a much cleaner solution that is actually maintainable.&lt;/p&gt;

&lt;p&gt;What do you think? &lt;/p&gt;

</description>
      <category>bugs</category>
      <category>enterprise</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Dependency Injection explained simply</title>
      <dc:creator>Boston Cartwright</dc:creator>
      <pubDate>Thu, 31 Dec 2020 14:48:15 +0000</pubDate>
      <link>https://forem.com/bstncartwright/what-is-dependency-injection-hhc</link>
      <guid>https://forem.com/bstncartwright/what-is-dependency-injection-hhc</guid>
      <description>&lt;p&gt;&lt;em&gt;Photo by Mpho Mojapelo on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;a href="https://bostonc.dev/posts/dependency-injection"&gt;originally published on bostonc.dev&lt;/a&gt;
&lt;/h5&gt;




&lt;p&gt;Ever since my first job as a developer, people I've worked with talked about dependency injection and how essential it was. Even with professional programming experience under my belt, it was difficult for me to understand what it really was. Online resources would use more jargon that only left me more confused. &lt;/p&gt;

&lt;p&gt;This post will hopefully provide a simple explanation for those new to software development and architecture on what dependency injection is and why it is needed.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://i.giphy.com/media/ATxVdsdpJ609i/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ATxVdsdpJ609i/giphy.gif" alt="two men singing in a car from *How I Met Your Mother*"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's say you have a car. For you I imagine you love to play music in your car (and especially love to sing along if you are like me 🎤 🎶). &lt;/p&gt;

&lt;p&gt;You got a nice deal on your car. There is a problem though, the stereo in your car is special. It can only play music from a CD which is welded into the stereo. This means that if you get tired of singing Kool &amp;amp; The Gang, you will have to go and get a whole new stereo and then replace your current stereo with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Stereo&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cdName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;speakers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cdName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cdName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speakers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;speakers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;speakers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;playMusic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cdName&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a lot of manual work and will take some time. Fortunately, stereos aren't actually built this way. Instead, they have a CD reader, in which you can put many CDs in it. It can read any CD as long as the stereo and the CD speak the same language (you can't put a BluRay disk in your stereo!). You can hold CDs and change it any time you want. This is dependency injection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Stereo&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;speakers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speakers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;speakers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cdName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;speakers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;playMusic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cdName&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may seem like an obvious way to go about it since we have been using CDs and stereos a long time (although going away with everything being streamed!). However, software is typically written tightly coupled as described in the scenario. Its normal to have an application getting data from an outside source such as a database. But what happens when the client wants it to connect to a different database? With dependency injection, it's as simple as switching them out like a CD in a stereo.&lt;/p&gt;




&lt;p&gt;Let's imagine we are writing an application to display current movies shown in theaters to a user. Take a look a this &lt;a href="https://en.wikipedia.org/wiki/Pseudocode"&gt;pseudocode&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// function to display movies to the user&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;displayMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// get movies&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// display movies&lt;/span&gt;
  &lt;span class="nx"&gt;showMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// function to get movies from the database&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// connect to our DB (currently a SQLDB)&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SQLDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// query for movies&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ExecuteQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movies&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;Above we have a simple function in order to get the movies data from a SQL database by connecting to it and executing a query, then finally displaying it to the user.&lt;/p&gt;

&lt;p&gt;This works, but is hard to test! In order to test it, we need to have a SQLDB running on any machine we test on populated with mock data. As well as in the future, if suddenly we needed to connect to a different database, such as a NOSQL database, then we have a lot of work to change.&lt;/p&gt;

&lt;p&gt;If we wanted to be able to test this easily or change databases, we need to loose the tight coupling from the application and the database. We can do this by defining an &lt;a href="https://www.cs.utah.edu/~germain/PPS/Topics/interfaces.html"&gt;interface&lt;/a&gt; for a DB with a set of methods it can call (the language spoken) and then ensure that any database we use fulfils that interface.&lt;/p&gt;

&lt;p&gt;Let's look at how this could be done (again, &lt;a href="https://en.wikipedia.org/wiki/Pseudocode"&gt;psuedocode&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// movie database interface&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MovieDB&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;GetAllMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;GetMovie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// .. other methods needed to manipulate movie database&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// class for MovieDB held on SQLDB&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;SQLMovieDB&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;MovieDB&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// variable to hold db object&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// constructor for when SQLMovieDB is created&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// connect to DB&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SQLDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// get all movies&lt;/span&gt;
  &lt;span class="nx"&gt;GetAllMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ExecuteQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// get a specific movie&lt;/span&gt;
  &lt;span class="nx"&gt;GetMovie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ExecuteQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM movies where movies.name is &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ... other methods to implement interface&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice! Now we have abstracted the movie database into an interface that can be implemented by our SQLMovieDB. Now to display the movies, we can do as so:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: For languages that don't support interfaces, you can pass additional parameters to functions to replicate the same behavior.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// function to display movies to the user&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;displayMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// get movies&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// display movies&lt;/span&gt;
  &lt;span class="nx"&gt;showMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// function to get movies from the database&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// connect to our DB&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;SQLMovieDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// query for movies&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetAllMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movies&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;&lt;a href="https://i.giphy.com/media/ToMjGpnXBTw7vnokxhu/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ToMjGpnXBTw7vnokxhu/giphy.gif" alt="woah"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is even easier to test! We can create a mock movie DB to be used in our tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MockMovieDB&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;MovieDB&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// don't need to do anything&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// get all movies&lt;/span&gt;
  &lt;span class="nx"&gt;GetAllMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SOME SUPER COOL MOVIE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;otheData&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;otherMovies&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// get a specific movie&lt;/span&gt;
  &lt;span class="nx"&gt;GetMovie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SOME SUPER COOL MOVIE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;otherData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ... other methods to implement interface&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can ensure for the tests that we use the MockMovieDB and easily mock the data without actually having to stand up a database server on the test machine.&lt;/p&gt;

&lt;p&gt;Finally, it makes it easy to use another database in the future if needed, for example, using a NOSQL database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// class for MovieDB held on NOSQLDB&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;NOSQLMovieDB&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;MovieDB&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;NOSQLDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// get all movies&lt;/span&gt;
  &lt;span class="nx"&gt;GetAllMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// get a specific movie&lt;/span&gt;
  &lt;span class="nx"&gt;GetMovie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ... other methods to implement interface&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to use this NOSQLMovieDB we only have to change one line in our &lt;code&gt;displayMovies&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// function to display movies to the user&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;displayMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// get movies&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// display movies&lt;/span&gt;
  &lt;span class="nx"&gt;showMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// function to get movies from the database&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// connect to our DB&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;NOSQLMovieDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;---- WE ONLY HAVE TO CHANGE HERE&lt;/span&gt;

  &lt;span class="c1"&gt;// query for movies&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GetAllMovies&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movies&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;&lt;a href="https://i.giphy.com/media/dWy2WwcB3wvX8QA1Iu/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/dWy2WwcB3wvX8QA1Iu/giphy.gif" alt="simple"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We could even move this to an environment variable if we so wanted. We can even eliminate the need for ever rewriting the &lt;code&gt;getMovies&lt;/code&gt; function by injecting a MovieDB implementor as a parameter!&lt;/p&gt;




&lt;p&gt;Once I really understood dependency injection, a whole world of great software design patterns opened up to me. By using these patterns my code has become cleaner and safer. &lt;/p&gt;

&lt;p&gt;Let me know what you think!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Special thanks to &lt;a href="https://github.com/AdamWhitehurst"&gt;Adam Whitehurst&lt;/a&gt; for helping prepare this post. 🤘&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>How to use Git Bisect 🕵️‍♂️</title>
      <dc:creator>Boston Cartwright</dc:creator>
      <pubDate>Wed, 02 Dec 2020 17:02:23 +0000</pubDate>
      <link>https://forem.com/bstncartwright/using-git-bisect-45ib</link>
      <guid>https://forem.com/bstncartwright/using-git-bisect-45ib</guid>
      <description>&lt;h5&gt;
  
  
  &lt;a href="https://bostonc.dev/posts/git-bisect"&gt;originally published on bostonc.dev&lt;/a&gt;
&lt;/h5&gt;




&lt;p&gt;Even though I don't have years of professional programming experience, there has been a number of times where a bug is reported on my application and I cannot find out what change introduced it. This ends up being extremely frustrating and hard to work around. Once I discovered git bisect, I never experienced this frustration again.&lt;/p&gt;



&lt;h2&gt;
  
  
  Git Bisect
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/docs/git-bisect"&gt;Git Bisect&lt;/a&gt;'s documentation has a great description:&lt;/p&gt;

&lt;p&gt;"This command uses a binary search algorithm to find which commit in your project’s history introduced a bug. You use it by first telling it a "bad" commit that is known to contain the bug, and a "good" commit that is known to be before the bug was introduced. Then git bisect picks a commit between those two endpoints and asks you whether the selected commit is "good" or "bad". It continues narrowing down the range until it finds the exact commit that introduced the change."&lt;/p&gt;

&lt;p&gt;As it says, &lt;code&gt;git bisect&lt;/code&gt; allows you to find which commit in your repository introduces a bug, or really any difference, such as the commit where performance increased, a specific wording was changed, or even a color change.&lt;/p&gt;

&lt;p&gt;This is especially useful in large projects with tens or hundreds of commits a day. Finding the specific commit where a bug was introduced can make fixing it increasingly simpler. Understanding the changes that caused the issue makes it easier to solve it. &lt;/p&gt;
&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The first step in using &lt;code&gt;git bisect&lt;/code&gt; is to find a commit where the bug did not exist yet. This can be really as far back as you want to go. Once you find that commit, keep the commit hash in a safe place. For this example, we will use &lt;code&gt;abc123&lt;/code&gt; as the hash.&lt;/p&gt;

&lt;p&gt;Then you can start the &lt;code&gt;git bisect&lt;/code&gt; session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect start
git bisect bad
git bisect good abc123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, &lt;code&gt;git bisect&lt;/code&gt; will checkout a commit in between the bad and good commits. At this point, you can test your program to see if the bug exists in this commit. &lt;/p&gt;

&lt;p&gt;If the bug exists, you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect bad
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it does not, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect good
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This process is then repeated until it finds the commit that introduces the bug. You will see an output similar to (along with a description of the commit):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;def456 is the first bad commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you have found the commit, can view the changes that it introduced, and hopefully squash that bug 🐞! &lt;/p&gt;

&lt;p&gt;You can exit the &lt;code&gt;git bisect&lt;/code&gt; by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect reset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;I've prepared an example application in which we can go through this together. It is a simple React app bootstrapped with &lt;a href="https://create-react-app.dev/"&gt;Create React App&lt;/a&gt;. You can see the code for this example &lt;a href="https://github.com/munkurious/git-bisect-example"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Here is what the application looks like:&lt;/p&gt;

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

&lt;p&gt;Pretty simple, just has some text as a form of a landing page.&lt;/p&gt;

&lt;p&gt;However, originally there was a cool React logo that was spinning on the page! This was not supposed to be removed but was. It looked something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DbEBkKhy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3q4e8xvhjq8ey21z2gpu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DbEBkKhy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3q4e8xvhjq8ey21z2gpu.png" alt="example application with logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now I try to keep my commit messages clear on what they are doing, so that finding where this happened would be simple but sadly this doesn't hold up in large projects. Commit messages sometimes end up being &lt;a href="https://twitter.com/nixcraft/status/1255706042345811968"&gt;less than helpful&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JwFF15k8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uog4mwwi167t7sh3ig6t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JwFF15k8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uog4mwwi167t7sh3ig6t.jpg" alt="writing useful commit message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this project, I did not do a great job of writing good commit messages. Finding the commit that removed the logo will be a lot of manual work as I will have to go through every commit's changes and look for where it is removed. However, with &lt;code&gt;git bisect&lt;/code&gt;, this is easy.&lt;/p&gt;

&lt;p&gt;First I find a commit where the logo is present. Because this is a small project I went to the first commit of the project (&lt;code&gt;66f768475cd0543370e086d6bea3a06bbc0dd2e0&lt;/code&gt;) and confirmed the logo is there.&lt;/p&gt;

&lt;p&gt;I then start a &lt;code&gt;git bisect&lt;/code&gt; session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git-bisect-example on master
❯ git bisect start
❯ git bisect bad
❯ git bisect good 66f768475cd0543370e086d6bea3a06bbc0dd2e0
Bisecting: 2 revisions left to &lt;span class="nb"&gt;test &lt;/span&gt;after this &lt;span class="o"&gt;(&lt;/span&gt;roughly 1 step&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;037a419be3488a3d2208abecdc49bda251b871a1] made some more changes :&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It brought me to the commit with the hash &lt;code&gt;037a419be3488a3d2208abecdc49bda251b871a1&lt;/code&gt;. This commit does not have the logo, thus I mark it as bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ git bisect bad
Bisecting: 0 revisions left to &lt;span class="nb"&gt;test &lt;/span&gt;after this &lt;span class="o"&gt;(&lt;/span&gt;roughly 0 steps&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;5e35e0026935c3c3808e87b5691d22d4650bd145] changed some text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This commit has the logo! I mark it as good:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ git bisect good
037a419be3488a3d2208abecdc49bda251b871a1 is the first bad commit
commit 037a419be3488a3d2208abecdc49bda251b871a1
Author: Boston Cartwright
Date:   Mon Jun 8 12:48:44 2020 &lt;span class="nt"&gt;-0400&lt;/span&gt;

    made some more changes :&lt;span class="o"&gt;)&lt;/span&gt;

 src/App.js | 1 -
 1 file changed, 1 deletion&lt;span class="o"&gt;(&lt;/span&gt;-&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see by the above output, &lt;code&gt;git bisect&lt;/code&gt; has successfully found the commit that introduced this bug, &lt;code&gt;037a419be3488a3d2208abecdc49bda251b871a1&lt;/code&gt;. Looking at the changes, I can see that it did truly remove the logo and I can plan on how to fix it.&lt;/p&gt;




&lt;p&gt;Obviously with larger repositories and many more commits this can be a big time saver to find which commit introduces the bug. I have used &lt;code&gt;git bisect&lt;/code&gt; a number of times now and it has been a huge help.&lt;/p&gt;

</description>
      <category>git</category>
      <category>bugs</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
