<?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>DEV Community: Josemy Duarte</title>
    <description>The latest articles on DEV Community by Josemy Duarte (@josemyduarte).</description>
    <link>https://dev.to/josemyduarte</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%2F419097%2F2b0cdc00-aa4d-4194-a08b-4961eadde2ac.jpeg</url>
      <title>DEV Community: Josemy Duarte</title>
      <link>https://dev.to/josemyduarte</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/josemyduarte"/>
    <language>en</language>
    <item>
      <title>How to shutdown a Go application gracefully</title>
      <dc:creator>Josemy Duarte</dc:creator>
      <pubDate>Sat, 29 Apr 2023 17:59:10 +0000</pubDate>
      <link>https://dev.to/josemyduarte/how-to-shutdown-a-go-application-gracefully-42fc</link>
      <guid>https://dev.to/josemyduarte/how-to-shutdown-a-go-application-gracefully-42fc</guid>
      <description>&lt;h1&gt;
  
  
  How to shutdown a Go application gracefully
&lt;/h1&gt;

&lt;p&gt;All this started by noticing that my Go applications showed an increased number of errors when I was shutting them down. After some investigation I found out that the problem was related to the lifecycle of the components of my application. Why was this happening? Because I was not shutting down my application gracefully. Meaning that I was not giving the opportunity to the components to finish their work before shutting down all of them. &lt;/p&gt;

&lt;p&gt;Let me explain this with an example.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Let's say that we have a web server that is using a database. When we receive a request we need to query the database to get the information that we need to return to the client. If we are not shutting down the application gracefully, we might receive an error when we try to query the database because the database connection might be closed before we can use it.  Also, we might still have some requests inflight and all of them will fail if the database connection is closed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;Easy, we need to give the opportunity to the components to finish their work before shutting down the application. In the case of the web server, we need to stop receiving new requests and wait for the inflight requests to finish. In the case of the database, we need to close the connection only after all the requests that are using it have finished.&lt;/p&gt;

&lt;p&gt;I noticed a pattern here. I had to shutdown the components in the reverse order that I started them. Meaning, that I had to shutdown the web server first and then the database. This way, I could make sure that the web server was not receiving new requests and that all the inflight requests had finished before closing the database connection. So, I decided to create a &lt;code&gt;Manager&lt;/code&gt; struct that will manage the lifecycle of my application. This struct will have a &lt;code&gt;Start&lt;/code&gt; method that will start all the components of my application and a &lt;code&gt;Shutdown&lt;/code&gt; method that will stop all the components of my application.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Let's see how this looks like in code. First, I defined a common interface for all the components of my application.&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;type&lt;/span&gt; &lt;span class="n"&gt;Component&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Name returns the identifier of the component (mainly for logging purposes)&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

    &lt;span class="c"&gt;// Start is called in order to start the component.&lt;/span&gt;
    &lt;span class="c"&gt;// The initReady channel should be closed when the component's initialisation has finished. &lt;/span&gt;
    &lt;span class="c"&gt;// Some starts are blocking so by closing the channel we signal the manager that it can move on to the next component.&lt;/span&gt;
    &lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initReady&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

    &lt;span class="c"&gt;// Shutdown is called to stop and cleanup the component.&lt;/span&gt;
    &lt;span class="c"&gt;// There is a limited time to do so which is controlled by the ctx.&lt;/span&gt;
    &lt;span class="n"&gt;Shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;

    &lt;span class="c"&gt;// StartTimeout returns timeout within which the component is expected to be start&lt;/span&gt;
    &lt;span class="n"&gt;StartTimeout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I defined the &lt;code&gt;Manager&lt;/code&gt; struct that will manage the lifecycle of my application. It allows to &lt;code&gt;Register&lt;/code&gt; new components and since it is important to shutdown the components in the reverse order that they were started, I decided to store them in a slice.&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;// Manager is responsible for managing all the component's lifecycle.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Manager&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;components&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Component&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Register registers a new component.&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;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Manager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="n"&gt;Component&lt;/span&gt;&lt;span class="p"&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;components&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&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;components&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;component&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 &lt;code&gt;Start&lt;/code&gt; method will start all the registered components of the application. It will iterate over the slice of components and call the &lt;code&gt;Start&lt;/code&gt; method of each one of them. It will also wait for the &lt;code&gt;initReady&lt;/code&gt; channel to be closed before moving on to the next component. This way, we can make sure that the components are started in the correct order. If the &lt;code&gt;Start&lt;/code&gt; method of a component returns an error, the &lt;code&gt;Start&lt;/code&gt; method of the &lt;code&gt;Manager&lt;/code&gt; will publish the error in the &lt;code&gt;errCh&lt;/code&gt; channel and return it.&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="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;Manager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting %d components...&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="nb"&gt;len&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;components&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;errCh&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&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;components&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Start all the components in order.&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;c&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;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;components&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Starting component %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;c&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="c"&gt;// Create a channel to signal that the component's initialization is done.&lt;/span&gt;
        &lt;span class="n"&gt;initReady&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;

        &lt;span class="c"&gt;// Start the component.&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="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;errCh&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initReady&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 the component's initialization to complete.&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;initReady&lt;/span&gt;&lt;span class="o"&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Component %s initialization completed&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;c&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="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;After&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="n"&gt;StartTimeout&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;errCh&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;StartTimeoutError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ComponentName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errCh&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// Check for errors during startup.&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;errCh&lt;/span&gt;&lt;span class="o"&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;errCh&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&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;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to start component %s: %w"&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="n"&gt;Name&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errCh&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Component %s started successfully&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;c&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="p"&gt;}&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All components started in %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&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;errCh&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;Shutdown&lt;/code&gt; method will stop all the registered components of the application. It will iterate over the slice of components in reverse order and call the &lt;code&gt;Shutdown&lt;/code&gt; method of each one of them and wait for it to finish before moving on to the next component. This way, we can make sure that the components are stopped in the correct order, and we can give them the opportunity to finish their work. If the &lt;code&gt;Shutdown&lt;/code&gt; method of a component returns an error, it will be added to the &lt;code&gt;errs&lt;/code&gt; slice, and it will continue with the next component. All the errors will be returned at the end of the method in a single error.&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="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;Manager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gracePeriod&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&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="n"&gt;log&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;"Shutting down %d components...&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="nb"&gt;len&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;components&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&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;errs&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;

    &lt;span class="n"&gt;shutdownDone&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&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;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Start shutting down all the components in reverse order.&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&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;components&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&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="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shutting down component %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;c&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="c"&gt;// Check for errors during shutdown.&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;errs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&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;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to shutdown component %s: %w"&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="n"&gt;Name&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;else&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Component %s shutdown successfully&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;c&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="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shutdownDone&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 the components shutdown to complete or timeout.&lt;/span&gt;
    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;shutdownDone&lt;/span&gt;&lt;span class="o"&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shutdown finished in %v&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;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;After&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gracePeriod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ShutdownTimeoutError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;TimeOut&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gracePeriod&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Check if there were any errors during shutdown.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&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;ShutdownError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;}&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;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shutdown completed successfully&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="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;We end up with a simple way to control the lifecycle of the components of our application. No component should be stopped without finishing its work, and no component should be started before all the components that it depends on have been started. We have complete control over the order in which the components are started and stopped.&lt;/p&gt;

&lt;p&gt;Feel free to check out the full code on &lt;a href="https://github.com/JosemyDuarte/ComponentManager"&gt;GitHub&lt;/a&gt;. There are some tests and a simple example of how to use the &lt;code&gt;Manager&lt;/code&gt; struct. &lt;/p&gt;

&lt;p&gt;Being honest, I don't know if this is the best way to manage the lifecycle of the components of a Golang application, or if I just reinvented the wheel. I would love to hear your thoughts on this. &lt;/p&gt;

&lt;p&gt;If you have any suggestions or improvements, you &lt;br&gt;
are more than welcome to open a pull request on the repository.&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why data-driven decision matters</title>
      <dc:creator>Josemy Duarte</dc:creator>
      <pubDate>Fri, 16 Jul 2021 09:04:15 +0000</pubDate>
      <link>https://dev.to/josemyduarte/why-data-driven-decision-matters-3k4f</link>
      <guid>https://dev.to/josemyduarte/why-data-driven-decision-matters-3k4f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“If we have data, let’s look at data. If all we have are opinions, let’s go with mine.”&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;― Jim Barksdale&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Businesses often make decisions based on opinion rather than facts. Why? I think it is mainly due to 3 main reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bias&lt;/strong&gt; - If I think A, most certainly my users/clients also think A&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt; - Planning, experimenting, analysing takes time and resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk&lt;/strong&gt; - Experimenting imply risk of something going wrong&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let me elaborate I little more on this reasons:&lt;/p&gt;

&lt;h4&gt;
  
  
  Bias
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;By following an empirical approach, we ensure that product changes are not driven by the most opinionated and vocal Netflix employees, but instead by actual data, allowing our members themselves to guide us toward the experiences they love.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://netflixtechblog.com/its-all-a-bout-testing-the-netflix-experimentation-platform-4e1ca458c15"&gt;&lt;strong&gt;―&lt;/strong&gt;The Netflix Tech Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Couldn't say it better. But also keep in mind that &lt;a href="https://www.goodreads.com/quotes/336994-the-only-thing-that-is-constant-is-change--"&gt;change is the only thing that it's constant&lt;/a&gt;. So keep measuring even after your experimentation has finished, since what was true 2 years ago might not be true today.&lt;/p&gt;

&lt;h4&gt;
  
  
  Speed
&lt;/h4&gt;

&lt;p&gt;Making a decision just for the sake of moving fast can backfire, as making a mistake can cause a greater delay than running an experiment to make a data-driven decision. &lt;/p&gt;

&lt;h4&gt;
  
  
  Risk
&lt;/h4&gt;

&lt;p&gt;You need to be very careful how you run your experiments, as doing something wrong can cause your customers to lose money, and consequently, you can lose customers and trust. This could lead managers to avoid making "big" changes and trying new things or simply trying &lt;em&gt;only&lt;/em&gt; things that can be done "safely". &lt;/p&gt;

&lt;h3&gt;
  
  
  Experimentation
&lt;/h3&gt;

&lt;p&gt;Making experimentation easy and safe will increase innovation. Also, keep in mind that It's all about feedback and validating hypothesis. You can't get feedback until it's in your customer's hands.&lt;/p&gt;

&lt;p&gt;Having barriers on innovation will have an impact on how fast your company grows. How to approach these issues? First, don't be afraid of your customer's feedback, use it to guide your product evolution. Second, &lt;strong&gt;make experiments safe and easy to measure&lt;/strong&gt;, which will lower the effort required to gather data to make informed decisions.&lt;/p&gt;

&lt;p&gt;How do we do that? Having technology and mechanisms that allow you to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run your experiments on a small subset of customers. That will allow you to test your hypothesis but also reduce the impact of any possible issue on your experiment.&lt;/li&gt;
&lt;li&gt;Monitor all relevant KPI. That allows you to have an eye on how the experiment is going and knowing if something is wrong at any given moment.&lt;/li&gt;
&lt;li&gt;Make it easy to turn off any ongoing experiment. If you notice any undesired result from your metrics, you will be able to stop it before it has a greater impact on your customers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Don't forget that simplicity is key for this to succeed. So avoid burying this under heavy processes and try to keep them as lightweight as possible, so engineers don't feel discouraged to run experiments.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>experiment</category>
      <category>agile</category>
    </item>
    <item>
      <title>Creating a Twitter Bot with Go</title>
      <dc:creator>Josemy Duarte</dc:creator>
      <pubDate>Sat, 13 Mar 2021 13:02:55 +0000</pubDate>
      <link>https://dev.to/josemyduarte/creating-a-twitter-bot-with-go-bl0</link>
      <guid>https://dev.to/josemyduarte/creating-a-twitter-bot-with-go-bl0</guid>
      <description>&lt;p&gt;I keep experimenting with go and bots, so this week I decided to create a Twitter bot. It's not the typical bot that just publishes things or does some scraping, this one will react to mentions; each time someone mentions the bot, it will reply with a "hello". This is possible through the &lt;a href="https://developer.twitter.com/en/docs/twitter-api/enterprise/account-activity-api/overview"&gt;Account Activity API&lt;/a&gt; of Twitter, which will call our service for every new event related to our bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Brief explanation
&lt;/h2&gt;

&lt;p&gt;The code is pretty simple and straightforward, so I will not get into too many details; there are 3 endpoints on our server:&lt;/p&gt;

&lt;h3&gt;
  
  
  POST &lt;code&gt;/webhook/twitter&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is where the behavior of our bot lives. So, in my case is only replying with "hello", but here is where you would make any customization in case you clone/fork it.&lt;/p&gt;

&lt;h3&gt;
  
  
  GET &lt;code&gt;/webhook/twitter&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;For security reasons, Twitter requires us to have an endpoint that will solve a CRC request. So we follow &lt;a href="https://developer.twitter.com/en/docs/twitter-api/enterprise/account-activity-api/guides/securing-webhooks"&gt;Twitter guidelines&lt;/a&gt; and that's what this endpoint is doing.&lt;/p&gt;

&lt;h3&gt;
  
  
  POST/GET... &lt;code&gt;/&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Nothing fancy. Just returning "Server is up and running" for you to make sure that the &lt;em&gt;server is up and running&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fork it, clone it, use it!
&lt;/h2&gt;

&lt;p&gt;Feel free to &lt;a href="https://github.com/JosemyDuarte/TwitterGoBot"&gt;clone/fork the repo&lt;/a&gt; and customize it to your need. You will find instructions to deploy it on &lt;a href="https://heroku.com/"&gt;Heroku&lt;/a&gt; or even try it on your machine if you want.&lt;/p&gt;

</description>
      <category>go</category>
      <category>twitter</category>
      <category>tutorial</category>
      <category>github</category>
    </item>
    <item>
      <title>Putting Text on an Image with Golang</title>
      <dc:creator>Josemy Duarte</dc:creator>
      <pubDate>Tue, 02 Mar 2021 11:37:02 +0000</pubDate>
      <link>https://dev.to/josemyduarte/putting-text-on-an-image-with-golang-551j</link>
      <guid>https://dev.to/josemyduarte/putting-text-on-an-image-with-golang-551j</guid>
      <description>&lt;p&gt;Since the beginning of my career, I have been focused on Java as my main programming language, but recently I switched to a company that uses Golang, and to help me to learn more about the language I decided to build something. &lt;/p&gt;

&lt;p&gt;The service that I build in summary just puts some text on a given image. Its main purpose is to help me create the posts that I publish on my Instagram account &lt;a href="https://www.instagram.com/devsquotes/"&gt;DevsQuotes&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I used to create my posts with Photoshop but it was taking me too much time to get a simple image ready, then I discovered &lt;a href="https://www.adobe.com/es/products/spark.html"&gt;Adobe Spark&lt;/a&gt; which simplified the flow a little, but with this service now is super simple since I integrated it with a Telegram Bot and now I just need to send a message and I have my image ready to be published. Yes, there is room for improvement, but keep in mind that this was just a PoC which mission was to help me get comfortable with GoLang and simplify the process to create images for my Instagram.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR Show me the code!
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Request struct {
    BgImgPath string
    FontPath  string
    FontSize  float64
    Text      string
}

func TextOnImg(request Request) (image.Image, error) {
    bgImage, err := gg.LoadImage(request.BgImgPath)
    if err != nil {
        return nil, err
    }
    imgWidth := bgImage.Bounds().Dx()
    imgHeight := bgImage.Bounds().Dy()

    dc := gg.NewContext(imgWidth, imgHeight)
    dc.DrawImage(bgImage, 0, 0)

    if err := dc.LoadFontFace(request.FontPath, request.FontSize); err != nil {
        return nil, err
    }

    x := float64(imgWidth / 2)
    y := float64((imgHeight / 2) - 80)
    maxWidth := float64(imgWidth) - 60.0
    dc.SetColor(color.White)
    dc.DrawStringWrapped(request.Text, x, y, 0.5, 0.5, maxWidth, 1.5, gg.AlignCenter)

    return dc.Image(), nil
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That piece of code makes all the magic. With the help of &lt;a href="https://github.com/fogleman/gg"&gt;Fogleman library&lt;/a&gt; manipulating images in Go is a breeze. Let's check what this is doing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bgImage, err := gg.LoadImage(request.BgImgPath)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It loads the image in which the text will be printed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;imgWidth := bgImage.Bounds().Dx()
imgHeight := bgImage.Bounds().Dy()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Records the &lt;code&gt;Width&lt;/code&gt; and &lt;code&gt;Height&lt;/code&gt; of the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dc := gg.NewContext(imgWidth, imgHeight)
dc.DrawImage(bgImage, 0, 0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates something like a canvas (or context) in which we are going to start working.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dc.LoadFontFace(request.FontPath, request.FontSize)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It loads the font to use on the message to be printed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x := float64(imgWidth / 2)
y := float64((imgHeight / 2) - 80)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Records the middle of the image on X and in Y it also subtracts 80 because I want the text to be a little bit above the middle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;maxWidth := float64(imgWidth) - 60.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define the maximum width that your text can occupy. Subtracting 60 from the total width of the image is like generating a margin, so our text does not reach the edge of our image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dc.SetColor(color.White)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are defining the color in which we are going to &lt;em&gt;paint/print&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dc.DrawStringWrapped(request.Text, x, y, 0.5, 0.5, maxWidth, 1.5, gg.AlignCenter)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints the content of &lt;code&gt;request.Text&lt;/code&gt; on our canvas in the middle of the image with an alignment centered. &lt;/p&gt;

&lt;p&gt;The result will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cHR6TYz---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3088s4mr8dx3afhsc3c.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cHR6TYz---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3088s4mr8dx3afhsc3c.jpeg" alt="PrinterExample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more context on how all this works and even try it by yourself if you want visit &lt;a href="https://github.com/JosemyDuarte/DevsQuotesPrinter"&gt;the DevsQuotesPrinter repository&lt;/a&gt;. It has instructions for you to be able to deploy it on GCP, Heroku or to try it locally, so feel free to play with it.&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Do I really need to test my code?</title>
      <dc:creator>Josemy Duarte</dc:creator>
      <pubDate>Sun, 28 Feb 2021 14:01:01 +0000</pubDate>
      <link>https://dev.to/josemyduarte/do-i-really-need-to-test-my-code-30po</link>
      <guid>https://dev.to/josemyduarte/do-i-really-need-to-test-my-code-30po</guid>
      <description>&lt;p&gt;It is difficult to find any developer who does not agree with the title of this publication, even more, if asked in a job interview. Although, some developers took what Kent Beck once said &lt;a href="https://stackoverflow.com/questions/153234/how-deep-are-your-unit-tests/153565#153565"&gt;"I get paid for &lt;strong&gt;code that works&lt;/strong&gt;, not for tests"&lt;/a&gt; as a license to not create tests at all. I think we should take his words with special care. He did not mean that you should not develop tests because you are not paid for that, but that you must &lt;em&gt;concentrate&lt;/em&gt; on your production code.&lt;/p&gt;

&lt;p&gt;Tests are important because they give you confidence when you make changes and ensures a certain level of quality in the service being tested. They also serve as some kind of documentation of the expected behavior of a piece of code. But everything needs moderation, no tests might be as harmful as too many bad tests. &lt;/p&gt;

&lt;p&gt;Now, if the title question creates debate, the following content might not be for all audiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should I test?
&lt;/h2&gt;

&lt;p&gt;I know of companies that do not care at all about test coverage, others that think anything below 90% is bad. So, &lt;em&gt;how much testing is enough?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need 100% Coverage?
&lt;/h3&gt;

&lt;p&gt;Continuing with Kent Beck quotes I would like to bring one of your tweets on this topic:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Being proud of 100% test coverage is like being proud of reading every word in the newspaper. Some are more important than others.&lt;/p&gt;

&lt;p&gt;--Kent Beck (@KentBeck) &lt;a href="https://twitter.com/kentbeck/status/812703192437981184"&gt;Dec 24, 2016&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, as pointed in his book &lt;a href="https://www.amazon.com/dp/0201616416/"&gt;Extreme Programming Explained: Embrace Change&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is impossible to test absolutely everything, without the tests being as complicated and error-prone as the code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Testing everything will probably lead you to perform non-orthogonal tests, which increases the likelihood that when you make a small change in your code, thousands of tests will be broken. Then, you spend more time fixing tests than creating &lt;strong&gt;code that works&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When making small changes causes many tests to break, developers are afraid to make changes because each time this happens they feel frustrated and unproductive. If we take into consideration that one of the reasons for testing is to feel safe when making changes to the production code, then we can agree that there is something wrong with the equation.&lt;/p&gt;

&lt;p&gt;So, no, I don't think you need 100% coverage. I know that is a controversial statement, there are some good reasons to argue the contrary, but I think that the pros of that aren't enough to aim for 100% coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is (not) a Unit Test?
&lt;/h2&gt;

&lt;p&gt;Sometimes is easier to define something by saying what is NOT, and Michael Feathers can help us with that. For him &lt;a href="https://www.artima.com/weblogs/viewpost.jsp?thread=126923"&gt;a test is not a unit test if:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It talks to the database&lt;br&gt;
It communicates across the network&lt;br&gt;
It touches the file system&lt;br&gt;
It can't run at the same time as any of your other unit tests&lt;br&gt;
You have to do special things to your environment (such as editing config files) to run it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You might ask: Why? Well, mainly because tests that do that sort of thing are generally slow and cause unstable tests. The idea of tests is to give you quick feedback on your code; If something broke or if you have the desired behavior; If you have tests that work sometimes and fail other times without obvious reasons, you will lose confidence in your tests, ignore them because "it is normal for these tests to fail".&lt;/p&gt;

&lt;p&gt;Finally, unit tests must be quick, they are designed to give you quick feedback. You should not have to think twice before executing them. If they are slow, they lose their reason. Developers will not execute them so often, they will avoid wasting that time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I test third-party libraries?
&lt;/h3&gt;

&lt;p&gt;Well, if you do it, for sure it won't be an easy task. Steve Freeman in his book &lt;a href="https://www.amazon.es/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627"&gt;Growing Object-Oriented Software, Guided by Tests&lt;/a&gt; has a couple of good arguments to persuade you to avoid it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Depending on the quality of the library might be hard to get the right state to be able to test it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When you use a third-party library, you must adapt to its design implementation. You gain the value of what they provide but lose some freedom in the implementation. Sometimes, that design is not easy to test and will require a lot of work just to establish the correct state to be able to test it. Also, you have to deal with the second point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pain to keep test up to date with upgrades to the library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even if you are using an open-source library and can redefine the API to facilitate testing and use for your purpose, you will have to spend some time each time a library update is required.&lt;/p&gt;

&lt;p&gt;So, what should we do? No tests at all? No. Define an adapter, test the adapter. And later test these adapters with focused integration tests to confirm your understanding of how the third-party API works.&lt;/p&gt;

&lt;p&gt;There are some exceptions where mocking third-party libraries can be helpful. We might use mocks to simulate behavior that is hard to trigger with the real library, such as throwing exceptions. Similarly, we might use mocks to test a sequence of calls, for example making sure that a transaction is rolled back if there’s a failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing private methods
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://www.amazon.es/Pragmatic-Unit-Testing-Junit-Programmers/dp/0974514012"&gt;Pragmatic Unit Testing&lt;/a&gt;, Dave Thomas and Andy Hunt write:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A private method usually is an implementation detail. Testing implementation details is not good for your health. Usually causes that when you do a small refactor many tests fail. You should be able to test your classes through its public methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing implementation Details
&lt;/h3&gt;

&lt;p&gt;Programmer tests should be sensitive to behavior changes and insensitive to structural changes. You write a new test when you need to fulfill a new requirement, no because you created a new method or class. That means that you should not write a new test just because you refactored the code, a refactor is a structural change, hence the behavior should remain the same.&lt;/p&gt;

&lt;p&gt;When you test implementation details instead of behavior there are a couple of things that can go wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Break when you refactor application code.  &lt;strong&gt;False negatives&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt; Not fail when you break the application code.  &lt;strong&gt;False positives&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one, because your test is highly coupled to the structure of your application code. The second one, because you are testing structure, not behavior.&lt;/p&gt;

&lt;p&gt;To put closure on this subject I would like to quote Ryan Fynke. In &lt;a href="https://teamgaslight.com/blog/testing-behavior-vs-testing-implementation"&gt;his article&lt;/a&gt; he found an elegant way to put the difference between testing implementation details and behavior:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  When I test for behavior, I’m saying:
&lt;/h3&gt;

&lt;p&gt;“I don’t care how you come up with the answer, just make sure that the answer is correct under this set of circumstances”&lt;/p&gt;
&lt;h3&gt;
  
  
  When I test for implementation, I’m saying:
&lt;/h3&gt;

&lt;p&gt;“I don’t care what the answer is, just make sure you do this thing while figuring it out.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;PD: Just for fun, read &lt;a href="http://edw519.posthaven.com/it-takes-6-days-to-change-1-line-of-code"&gt;this&lt;/a&gt; story.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>codequality</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>My path to AWS Solutions Architect - Associate certification</title>
      <dc:creator>Josemy Duarte</dc:creator>
      <pubDate>Sun, 17 Jan 2021 19:43:50 +0000</pubDate>
      <link>https://dev.to/josemyduarte/my-path-to-aws-solutions-architect-associate-certification-3j89</link>
      <guid>https://dev.to/josemyduarte/my-path-to-aws-solutions-architect-associate-certification-3j89</guid>
      <description>&lt;p&gt;I finally got the AWS certification 🤓! I read many stories about how people prepare to pass this exam. Everyone has their own way of learning so I wanted to build my own strategy out of all the things that I felt could help me from the experiences of others. Now I want to share how I did it, hoping I can help someone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some background
&lt;/h3&gt;

&lt;p&gt;For me, scheduling the exam was difficult because I always felt that I was not ready for it, that I could study more. But in January 2020, I found the strength to schedule my exam; I didn't feel like I was 100% ready, but I didn't want to put it off. How did I convince myself to do it? I thought that even if I didn't pass the exam, I would get the experience of doing it and know how difficult it was (maybe it was easier than I was imagining) and what knowledge required a little more of work on my side. In the worst case, I could use that experience to pass it on a second try, right? So I scheduled it for the end of March. Unfortunately, COVID had other plans. Due to the lockdown, my exam was canceled. I forgot about certification for a few months until I noticed that the year was ending and I hadn't rescheduled the exam, so again I had to convince myself to schedule an exam. Now it was for the 7th of January 2021, and this is what I did to prepare myself...&lt;/p&gt;

&lt;h3&gt;
  
  
  A Cloud Guru
&lt;/h3&gt;

&lt;p&gt;I found that &lt;a href="https://acloudguru.com/"&gt;A Cloud Guru&lt;/a&gt; offered a specific course that prepares you to pass the AWS Solutions Architect exam, so I decided to give it a try. It has some "Exam Tips", some quizzes to test your knowledge, a certification-like exam, and some labs that you can follow with a demo account that they provide you so you can try everything they teach you, without using your own AWS account and no unwanted charges. I found those labs helpful for hands-on experience with products that I never had a chance to test. In addition, there is a public forum where people can ask the instructors questions. Sometimes you find your doubts already answered.&lt;/p&gt;

&lt;h3&gt;
  
  
  FreeCodeCamp
&lt;/h3&gt;

&lt;p&gt;The last two weeks before my exam, I watched the &lt;a href="https://www.youtube.com/watch?v=Ia-UEYYR44s"&gt;FreeCodeCamp video&lt;/a&gt;. It is an 11-hour video that describes and shows all AWS services related to Solutions Architect certification. It has a nice cheat sheet at the end of each section (pay special attention to those).&lt;/p&gt;

&lt;h3&gt;
  
  
  Jon Bonso's Practice Exams
&lt;/h3&gt;

&lt;p&gt;Reading about people's recommendations on preparing for certification, I came across many recommendations for the &lt;a href="https://www.udemy.com/course/aws-certified-solutions-architect-associate-amazon-practice-exams-saa-c02/"&gt;Jon Bonso Practice Exams&lt;/a&gt;. In the end, you don't know how good your progress is if you don't measure it. The Udemy course gave me 6 practice exams with the same number of questions you face for certification. The best part is that once the exam is over, it not only tells you whether or not you passed but shows you all your wrong answers with a detailed reason of why your choice was wrong and why the other option was better. I found that explaining why my reasoning was wrong gave me a better understanding of AWS services.&lt;/p&gt;

&lt;p&gt;So the day before my exam I took all the practice tests again to see if I could pass them on the first try and feel comfortable with the type of questions and the time constraints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advise
&lt;/h3&gt;

&lt;p&gt;I would recommend people to read the FAQs of the services tested in this certification. I didn't, and I think that had some repercussions on my final score. I was too focused on taking practice tests and watching the videos that I didn't read the FAQs. Don't miss out on those points and take a few minutes to read those pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pass the exam and celebrate!
&lt;/h3&gt;

&lt;p&gt;And that was all, with those 3 things I was able to pass my certification. I wish you all the best if you are preparing for it! &lt;/p&gt;

&lt;p&gt;Also, keep in mind that A Cloud Guru subscription may not be suitable for everyone; I mean, it costs more than AWS certification alone. I'd say it's useful if you want to learn other things too (it has courses for other certifications and for other cloud providers). Alternatively, you can follow the FreeCodeCamp labs with your AWS free tier account and just remember to clean up all resources to avoid unplanned charges.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>certification</category>
    </item>
    <item>
      <title>How to automate tests for webhooks</title>
      <dc:creator>Josemy Duarte</dc:creator>
      <pubDate>Thu, 24 Dec 2020 12:30:10 +0000</pubDate>
      <link>https://dev.to/josemyduarte/how-to-automate-tests-for-webhooks-2da5</link>
      <guid>https://dev.to/josemyduarte/how-to-automate-tests-for-webhooks-2da5</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Has it happened to you that you are coding a test that requires you to wait for a webhook notification? It is a problem because normally the third-party service is outside your network and your machine will not hear their notification unless you provide them with your public IP, and sometimes the public IP is not a feasible option.&lt;/p&gt;

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

&lt;p&gt;The automated tests that I have seen for these scenarios aren't too pretty. So maybe there is a better/prettier way to do this, but I wanted to share my approach in case anyone finds it useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;When your code needs to interact with a third party, you should probably take some time to read their documentation to learn how to make requests to them and how they will respond. &lt;/p&gt;

&lt;p&gt;Unfortunately, sometimes their documentation is out of date and when that happens your trust in their documentation disappears. Therefore, you will want to see for yourself that everything really works as expected and be prepared for any undocumented behavior that you encounter.&lt;/p&gt;

&lt;p&gt;Besides that, I think it's useful to have tests between my code and anything outside my control to be able to know that everything works as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  How?
&lt;/h2&gt;

&lt;p&gt;I used &lt;a href="https://www.testcontainers.org/"&gt;testcontainer&lt;/a&gt; to integrate into my tests the lifecycle of the Docker containers that I required. Testcontainer lets me forget about having to run &lt;code&gt;docker run&lt;/code&gt; and &lt;code&gt;docker stop&lt;/code&gt; before and after running any of my tests, as it integrates those commands with the start and finish of related tests.&lt;/p&gt;

&lt;p&gt;I used &lt;a href="https://ngrok.com/"&gt;ngrok&lt;/a&gt; to open a tunnel from the Internet to my container so the webhook could target the server waiting on my test. In other words, it allows me to have an URL for my public IP and makes accessible my machine from outside my private network.&lt;/p&gt;

&lt;p&gt;And a small web service that will be listening for any request made to the Ngrok URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proposal
&lt;/h2&gt;

&lt;p&gt;Putting all the pieces together this is more or less what I build to be able to automate a webhook test.&lt;/p&gt;

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

&lt;p&gt;To illustrate what I did I made a dummy project that you can find &lt;a href="https://github.com/JosemyDuarte/testcontainer_webhook_poc"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please, feel free to suggest improvements and suggestions 😉&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://josemyduarte.github.io/2020-12-24-testing-webhooks/"&gt;josemyduarte.github.io&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>docker</category>
      <category>testing</category>
      <category>automation</category>
    </item>
    <item>
      <title>Earthly: building automation tool</title>
      <dc:creator>Josemy Duarte</dc:creator>
      <pubDate>Mon, 13 Jul 2020 08:33:17 +0000</pubDate>
      <link>https://dev.to/josemyduarte/earthly-building-automation-tool-7ga</link>
      <guid>https://dev.to/josemyduarte/earthly-building-automation-tool-7ga</guid>
      <description>&lt;p&gt;There is a new building automation tool in the neighborhood named &lt;a href="https://www.earthly.dev/"&gt;Earthly&lt;/a&gt;. Its intention is to simplify CI pipelines, but nothing like an image to explain it better:&lt;/p&gt;

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

&lt;p&gt;I would describe it as a &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;docker multistage build&lt;/a&gt; with batteries. It actually has a Docker-like syntax. &lt;/p&gt;

&lt;p&gt;These are some features right from their &lt;a href="https://github.com/earthly/earthly"&gt;repo&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;🐳 &lt;strong&gt;Build anything via containers&lt;/strong&gt; - build container images or standalone artifacts (eg binaries, packages, arbitrary files)&lt;/p&gt;

&lt;p&gt;🛠 &lt;strong&gt;Programming language agnostic&lt;/strong&gt; - allows use of language-specific build tooling&lt;/p&gt;

&lt;p&gt;♻️ &lt;strong&gt;Reproducible builds&lt;/strong&gt; - does not depend on user's local installation. Runs the same locally, as in CI&lt;/p&gt;

&lt;p&gt;⛓ &lt;strong&gt;Parallelism that just works&lt;/strong&gt; - builds in parallel without special considerations the user has to make&lt;/p&gt;

&lt;p&gt;🏠 &lt;strong&gt;Mono-repo friendly&lt;/strong&gt; - ability to split the build definitions across a vast directory hierarchy&lt;/p&gt;

&lt;p&gt;🏘 &lt;strong&gt;Multi-repo friendly&lt;/strong&gt; - ability to import builds or artifacts from other repositories&lt;/p&gt;

&lt;h3&gt;
  
  
  Building something with Earthly
&lt;/h3&gt;

&lt;p&gt;Some days ago while taking a look at &lt;a href="https://quarkus.io/"&gt;Quarkus&lt;/a&gt; I found &lt;a href="https://quarkus.io/guides/funqy-amazon-lambda"&gt;Funqy&lt;/a&gt;, part of Quarkus’s serverless strategy that aims to provide a portable Java API to write functions deployable to various FaaS environments like AWS Lambda, Azure Functions, Knative, and Knative Events (Cloud Events). So I decided to see how easy would it be to build a simple "Hello World" with &lt;strong&gt;Funqy&lt;/strong&gt; and &lt;strong&gt;Earthly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'm not going to focus on the Funqy part since I simply followed their &lt;a href="https://quarkus.io/guides/funqy"&gt;guide&lt;/a&gt;. I wanted to know how complicated it would be to define a &lt;code&gt;build.earth&lt;/code&gt; file that allowed me to test and build a native quarkus application. This was the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; quay.io/quarkus/centos-quarkus-maven:20.1.0-java11&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /java-example&lt;/span&gt;

deps:
    COPY pom.xml ./
    RUN mvn -B de.qaware.maven:go-offline-maven-plugin:1.2.5:resolve-dependencies
    SAVE IMAGE

build:
    FROM +deps
    COPY src src
    RUN mvn -Pnative clean package
    SAVE ARTIFACT target/ /target AS LOCAL target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that file, I am creating a reproducible build that will create a &lt;code&gt;target&lt;/code&gt; folder with my artifacts.&lt;/p&gt;

&lt;p&gt;As said before, it is very similar to Dockerfile syntax. Apart from just a few new intuitive commands, if you know Docker you will get comfortable with Earthly really fast.&lt;/p&gt;

&lt;h4&gt;
  
  
  Describing build.earth
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;base&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This section initializes the build environment, it is like a base for all other steps, it applies to all "targets".&lt;/p&gt;

&lt;p&gt;(1) Base Docker image&lt;/p&gt;

&lt;p&gt;(2) Setting working directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(1) FROM quay.io/quarkus/centos-quarkus-maven:20.1.0-java11
(2) WORKDIR /java-example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;deps&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This section gathers all my project's dependencies.&lt;/p&gt;

&lt;p&gt;(3) Target's name&lt;/p&gt;

&lt;p&gt;(4) Copy the &lt;code&gt;pom.xml&lt;/code&gt; to allow earthly to create a layer/cache of the dependencies of my application.&lt;/p&gt;

&lt;p&gt;(5) Runs &lt;code&gt;maven&lt;/code&gt; and download all my application dependencies.&lt;/p&gt;

&lt;p&gt;(6) Saves this container as an image. This allows the following steps/targets to use all the hard work done by these commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(3) deps:
    (4) COPY pom.xml ./
    (5) RUN mvn -B de.qaware.maven:go-offline-maven-plugin:1.2.5:resolve-dependencies
    (6) SAVE IMAGE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;build&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This section actually builds my artifact.&lt;/p&gt;

&lt;p&gt;(7) Target's name&lt;/p&gt;

&lt;p&gt;(8) Defines that this target is built from &lt;code&gt;deps&lt;/code&gt; target. There is a dependency.&lt;/p&gt;

&lt;p&gt;(9) Copy all my source code into the container.&lt;/p&gt;

&lt;p&gt;(10) Maven command to execute all my tests and build my artifact.&lt;/p&gt;

&lt;p&gt;(11) Saves output into my machine on a &lt;code&gt;target&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(7) build:
    (8) FROM +deps
    (9) COPY src src
    (10) RUN mvn -Pnative clean package
    (11) SAVE ARTIFACT target/ /target AS LOCAL target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, this is a toy example. You can have earthly files way more complicated (even multi-repo projects). It was also really easy to integrate it into Github Actions. This is the repo for anyone who might want to take a deeper look &lt;a href="https://github.com/JosemyDuarte/earthly-quarkus-poc"&gt;Earthly Repository&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Originaly posted on my &lt;a href="https://josemyduarte.github.io/2020-07-12-building-with-earthly/"&gt;personal blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>tutorial</category>
      <category>github</category>
      <category>docker</category>
    </item>
    <item>
      <title>AWS Lambda: Quarkus vs Plain Java</title>
      <dc:creator>Josemy Duarte</dc:creator>
      <pubDate>Mon, 29 Jun 2020 05:49:09 +0000</pubDate>
      <link>https://dev.to/josemyduarte/aws-lambda-quarkus-vs-plain-java-25l9</link>
      <guid>https://dev.to/josemyduarte/aws-lambda-quarkus-vs-plain-java-25l9</guid>
      <description>&lt;p&gt;In my current job I've been using &lt;a href="https://aws.amazon.com/es/lambda/"&gt;AWS Lambda&lt;/a&gt; with plain Java 8, and to be honest, the first time this didn't sound too good for me. I mean, don't get me wrong, I'm mainly a Java Developer, but from previous experiences, I know how slow a Spring Boot app can be to start and the fact that serverless functions have what it's known as &lt;a href="https://en.wikipedia.org/wiki/Cold_start_(computing)"&gt;"Cold Start"&lt;/a&gt; didn't make too much sense for me.&lt;/p&gt;

&lt;p&gt;However, they didn't have too many problems with cold starts because first, plain Java (no framework) is faster than SpringBoot and second for those services that it is unaffordable a cold start there is something called "Warm Up" which previously it was just a CRON that would make a call to your Lambda to keep it alive and avoid cold starts, but now AWS has released a new feature called &lt;a href="https://aws.amazon.com/blogs/compute/new-for-aws-lambda-predictable-start-up-times-with-provisioned-concurrency/"&gt;"Provisioned Capacity"&lt;/a&gt; which will initialize the requested number of execution environments so they can be ready to respond to invocations.&lt;/p&gt;

&lt;p&gt;On the other hand, not so long ago I saw a demonstration given by a RedHat employee of their new project &lt;a href="https://quarkus.io/"&gt;Quarkus&lt;/a&gt;. It showed how incredibly fast it was to start a Java app and how well it works with Kubernetes, as Quarkus was meant to make Java more cloud-friendly.&lt;/p&gt;

&lt;p&gt;Just a few days ago, my brain decided to relate AWS Lambda with plain Java (as in my current job) and Quarkus, and I was wondering what the results would be in terms of cold start, memory, and speed for the following requests. So this is my experiment, probably not the most scientifically accurate, but I hope it gives you an idea of ​​the performance of these technologies with AWS Lambda.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiment
&lt;/h2&gt;

&lt;p&gt;I developed two simple projects: one with Java 8 with the default DynamoDB client and the other with Quarkus and the Quarkus DynamoDB client. Both projects will simply print the received request, query an existing DynamoDB item, and return it. At the end of the post, you will find the repositories if you want to play around with them (note that the code is not beautiful, it was developed just for the sake of this experiment). And these are my findings:&lt;/p&gt;

&lt;h3&gt;
  
  
  Plain Java 8
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Code
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloLambdaHandler&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RequestHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GameScoreRequest&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DynamoGameScore&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DynamoGameScore&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;GameScoreRequest&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;GameScoreRepository&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GameScoreRepository&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserId&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;orElseThrow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;NoSuchElementException:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &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;h4&gt;
  
  
  Logs
&lt;/h4&gt;

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

&lt;h3&gt;
  
  
  Quarkus Java 11
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Code
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Named&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestLambda&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;RequestHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;GameScoreRequest&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;DynamoGameScore&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nc"&gt;GameScoreRepository&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DynamoGameScore&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;GameScoreRequest&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &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;h4&gt;
  
  
  Logs
&lt;/h4&gt;

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

&lt;p&gt;So, in terms of cold start, we can appreciate that for the first request Plain Java 8 took almost &lt;strong&gt;24800ms&lt;/strong&gt; to finish while Quarkus did it in less than half with &lt;strong&gt;9000ms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The following requests with the function "hot" took Plain Java 8 an average of &lt;strong&gt;484.78ms&lt;/strong&gt;. While for Quarkus it took an average of &lt;strong&gt;503.55 ms&lt;/strong&gt;. Since these numbers are only for 3 requests and the numbers are very close to each other, I would dare to say that they would probably converge to the same number with a larger sample. Anyway, we can accept that after the cold start, the following requests seem to last more or less the same in Plain Java 8 or Quarkus.&lt;/p&gt;

&lt;p&gt;In terms of memory, it's fair to note that Quarkus (&lt;strong&gt;172mb&lt;/strong&gt;) required more memory than Plain Java 8 (&lt;strong&gt;137mb&lt;/strong&gt;). But keep in mind that Quarkus provides us with a dependency injection feature (among other things) that our other option doesn't provide.&lt;/p&gt;

&lt;p&gt;Yeah, I know, probably I should try making 1K requests and take the average or probably my code is not fair with one of the subjects under test, I'm completely open to suggestions, but what I can guarantee is that I did this 3 times (destroying all the infrastructure and creating it again) and the results were similar.&lt;/p&gt;

&lt;p&gt;Another point to take into consideration is the size of the package uploaded to AWS. We can appreciate that in this case, Quarkus is heavier than Plain Java 8.&lt;/p&gt;

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

&lt;p&gt;PD: I know there is a feature in Quarkus that allows us to produce a native app, which could have a faster cold start, but so far I have not been able to get it to work with AWS Lambda. When I make it work I will publish my findings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repositories
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/JosemyDuarte/quarkus-terraform-lambda-demo/tree/dynamo-terraform"&gt;Quarkus&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/JosemyDuarte/poc-plain-java-lambda-terraform/tree/dynamo-terraform"&gt;Plain Java 8&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>java</category>
      <category>quarkus</category>
    </item>
  </channel>
</rss>
