<?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: Uddeshya Singh</title>
    <description>The latest articles on DEV Community by Uddeshya Singh (@uds5501).</description>
    <link>https://dev.to/uds5501</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%2F367185%2Fe461b9c0-92c1-45ce-9026-4b89c7c2bc18.jpeg</url>
      <title>DEV Community: Uddeshya Singh</title>
      <link>https://dev.to/uds5501</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/uds5501"/>
    <language>en</language>
    <item>
      <title>Weird rants of a new Devops + Backend engineer 😤 [22 June 21] </title>
      <dc:creator>Uddeshya Singh</dc:creator>
      <pubDate>Tue, 22 Jun 2021 17:37:27 +0000</pubDate>
      <link>https://dev.to/uds5501/weird-rants-of-a-new-devops-backend-engineer-22-june-21-41f0</link>
      <guid>https://dev.to/uds5501/weird-rants-of-a-new-devops-backend-engineer-22-june-21-41f0</guid>
      <description>&lt;p&gt;Welcome to the weird notes of a new DevOps and Backend engineer. This is my (quite open) notebook on what was all the stuff I read and learnt. Not necessarily tech, you can just read on and understand what I am rambling on about.&lt;/p&gt;

&lt;h3&gt;
  
  
  [22 June 2021]
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Stuff I learnt 📝
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Opentelemetry logs are painful as fuck. Nothing official in terms of documentation :) I swear to god I feel I will find a good implementation and I will DOCUMENT IT FFS.&lt;/li&gt;
&lt;li&gt;The other night I jotted down a blogpost for traces + opentelemetry + sentry. I hope folks would love it. &lt;a href="https://levelup.gitconnected.com/golang-opentelemetry-and-sentry-the-underrated-distributed-tracing-stack-69dcda886ffe"&gt;Golang, Opentelemetry, and Sentry — The Underrated Distributed Tracing Stack&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Also, fluentd ---&amp;gt; OTEL Collector integration? YOU ARE PAINFUL :) Idk what kubernetes service guide I need to revisit because I am sure af not getting anywhere in this respect.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stuff I need to check out tomorrow? 📅
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Get done with one more exam.&lt;/li&gt;
&lt;li&gt;Setup the log system locally and see if it works.&lt;/li&gt;
&lt;li&gt;Upload the rules files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stuff I want to work some day in future. 🔭
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Go through the exporter fix PR in the weekend maybe. Or if time allows tomorrow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for listening to the rant.&lt;br&gt;
Uddeshya Singh,&lt;br&gt;
Signing off.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Weird rants of a new Devops + Backend engineer 😤 [19 June 21] 
</title>
      <dc:creator>Uddeshya Singh</dc:creator>
      <pubDate>Fri, 18 Jun 2021 18:38:27 +0000</pubDate>
      <link>https://dev.to/uds5501/weird-rants-of-a-new-devops-backend-engineer-19-june-21-1i18</link>
      <guid>https://dev.to/uds5501/weird-rants-of-a-new-devops-backend-engineer-19-june-21-1i18</guid>
      <description>&lt;p&gt;Welcome to the weird notes of a new DevOps and Backend engineer. This is my (quite open) notebook on what was all the stuff I read and learnt. Not necessarily tech, you can just read on and understand what I am rambling on about.&lt;/p&gt;

&lt;h3&gt;
  
  
  [19 June 2021]
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Stuff I learnt 📝
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;So, the current &lt;strong&gt;opentelemetry&lt;/strong&gt; &lt;code&gt;sentry-exporter&lt;/code&gt; is indeed incomplete right now. I investigated the elastic APM exporter and realised that Sentry one is just not using it's full capabilities yet. You need to run &lt;code&gt;span.Events()&lt;/code&gt; to get a list of events which can be further converted into &lt;code&gt;*sentry.Event&lt;/code&gt;.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sUqrRncZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2bt8zf3hn6xo17nlz7jv.png" alt="Sentry Error"&gt;
&lt;/li&gt;
&lt;li&gt;Also, in the prometheus-operator helm chart, we figured out how to add additional rules without having to "upgrade the chart" without putting in new values in &lt;code&gt;values.yaml&lt;/code&gt;. Just create a new &lt;strong&gt;PrometheusRule&lt;/strong&gt; object as a rule file and the ConfigMaps will auto grab it.&lt;/li&gt;
&lt;li&gt;PS: I am talking about this operator here : &lt;a href="https://github.com/prometheus-operator/kube-prometheus"&gt;kube-prometheus&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stuff I need to check out tomorrow? 📅
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How do i link a sentry span and a sentry issue.&lt;/li&gt;
&lt;li&gt;Talk with team and refine the requirements because hell no, Sentry is not a logging platform (or I am an idiot)&lt;/li&gt;
&lt;li&gt;Get vaccinated ffs 😢&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stuff I want to work some day in future. 🔭
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IF&lt;/strong&gt; I manage to pull this issue linking stuff off, I think I will contribute this to opentelemetry collector exporter. My first cloud native contribution &lt;em&gt;might&lt;/em&gt; be on its way idk man.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for listening to the rant.&lt;/p&gt;

&lt;p&gt;Uddeshya Singh,&lt;br&gt;
Signing off.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>devjournal</category>
      <category>kubernetes</category>
      <category>distributedsystems</category>
    </item>
    <item>
      <title>Weird rants of a new Devops + Backend engineer 😤 [18 June 21] </title>
      <dc:creator>Uddeshya Singh</dc:creator>
      <pubDate>Thu, 17 Jun 2021 18:30:26 +0000</pubDate>
      <link>https://dev.to/uds5501/weird-rants-of-a-new-devops-backend-engineer-18-june-21-4on</link>
      <guid>https://dev.to/uds5501/weird-rants-of-a-new-devops-backend-engineer-18-june-21-4on</guid>
      <description>&lt;p&gt;Welcome to the weird notes of a new DevOps and Backend engineer. This is my (quite open) notebook on what was all the stuff I read and learnt. Not necessarily tech, you can just read on and understand what I am rambling on about.&lt;/p&gt;

&lt;h3&gt;
  
  
  [18 June 2021]
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Stuff I learnt 📝
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I finally created my own Docker image of a gin-app and deployed it in a kubernetes pod.&lt;/li&gt;
&lt;li&gt;The biggest challenge? Connecting the 2 pods, our &lt;code&gt;otlp-example&lt;/code&gt; and the &lt;code&gt;opentelemetry-collector&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;I needed to connect from pod A to port 4317 of pod B. Ofcourse, i had exposed the port in pod B using &lt;strong&gt;NodePort&lt;/strong&gt; yet it didn't seem to work.&lt;/li&gt;
&lt;li&gt;What finally worked? Instead of using &lt;code&gt;0.0.0.0:4317&lt;/code&gt;, I just needed to use &lt;code&gt;otel-collector.observability.svc.cluster.local:4317&lt;/code&gt; psst, it's the port name (or deployment name? not sure) , then namespace, then service and so on, which is exposed by a Node Port in this other service.&lt;/li&gt;
&lt;li&gt;MAN ELASTIC APM IS AMAZING. LIKE. SO AMAZING TO LOOK AT THE TRACING &amp;lt;3
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CMvGNoKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lxarj2i186c1lq39p48z.png" alt="Elastic APM Tracing"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stuff I need to check out tomorrow? 📅
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Plan on figuring out how to collect logs from a pod using fluentD and exporting it to our dear &lt;code&gt;openetelemetry-collector&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Use env vars to toggle the GRPC connection port.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stuff I want to work some day in future. 🔭
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Nothing today&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for listening to the rant.&lt;br&gt;
Uddeshya Singh,&lt;br&gt;
Signing off.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>devjournal</category>
      <category>distributedsystems</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Weird rants of a new Devops + Backend engineer 😤 [17 June 21] </title>
      <dc:creator>Uddeshya Singh</dc:creator>
      <pubDate>Wed, 16 Jun 2021 22:10:32 +0000</pubDate>
      <link>https://dev.to/uds5501/weird-rants-of-a-new-devops-backend-engineer-17-june-21-57l4</link>
      <guid>https://dev.to/uds5501/weird-rants-of-a-new-devops-backend-engineer-17-june-21-57l4</guid>
      <description>&lt;p&gt;Welcome to the weird notes of a new DevOps and Backend engineer. This is my (quite open) notebook on what was all the stuff I read and learnt. Not necessarily tech, you can just read on and understand what I am rambling on about.&lt;/p&gt;

&lt;h3&gt;
  
  
  [17 June 2021]
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Stuff I learnt 📝
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Opentelemetry's sentry exporter is pretty cool, even thought it's specifically for traces right now, it does its job well.&lt;/li&gt;
&lt;li&gt;The sidecar architecture for opentelemetry-collector will work the best for a scenario. The engineers thought out the agent, collector interface pretty good. &lt;/li&gt;
&lt;li&gt;The Traces specification and the TraceID stuff is good too, I just hope there was more sync between the published package and the github repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stuff I need to check out tomorrow? 📅
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Need to show the instrumentation demo to the lead.&lt;/li&gt;
&lt;li&gt;Probably will need to checkout Elastic APM exporters for these traces.&lt;/li&gt;
&lt;li&gt;See if sentry can support any logging :)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stuff I want to work some day in future. 🔭
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Checking how opentelemetry trace back the traces by the ID.&lt;/li&gt;
&lt;li&gt;WTF is going on with those spans? Why do they provide us with new contexts?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for listening to the rant.&lt;/p&gt;

&lt;p&gt;Uddeshya Singh,&lt;br&gt;
Signing off.&lt;/p&gt;

</description>
      <category>opentelemetry</category>
      <category>devops</category>
      <category>headers</category>
      <category>notes</category>
    </item>
    <item>
      <title>Bare Metal instances and Hardware acceleration | Solutions for an organization</title>
      <dc:creator>Uddeshya Singh</dc:creator>
      <pubDate>Fri, 27 Nov 2020 18:31:25 +0000</pubDate>
      <link>https://dev.to/uds5501/deploying-android-emulators-on-aws-ec2-2-3-bare-metal-instances-and-hardware-acceleration-solutions-for-an-organization-47l9</link>
      <guid>https://dev.to/uds5501/deploying-android-emulators-on-aws-ec2-2-3-bare-metal-instances-and-hardware-acceleration-solutions-for-an-organization-47l9</guid>
      <description>&lt;p&gt;"You can invest more into android emulator hosting hardware (i.e. get bare metal instances) and reap the benefits later" will be the tagline I would start with because that really is the gist of this entire post (minus some really cool demonstration scripts I've got for you)&lt;/p&gt;

&lt;h1&gt;
  
  
  Make your emulators Faster! 💥
&lt;/h1&gt;

&lt;p&gt;Let's pick up from where we left off and talk about making your emulators faster. In the normal t2 instances, as we know, there is a hypervisor layer on top of the instance hardware, hence abstracting the hardware layer from the emulator we want to run on it, and thus, we can't use out good old hardware acceleration on top of it. &lt;/p&gt;

&lt;p&gt;But what if, we take away the hypervisor layer? No, you can't do it with a piece of code but you can definitely get it by investing some odd $4 per hour and get a machine that can run 40 emulators at once (tried and tested statistic).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz91s964fl5ntv2yuhh5m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz91s964fl5ntv2yuhh5m.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's exactly how we pulled off a mass testing fleet with a variety of emulators all running simultaneously on a single machine. Since the hypervisor layer is stripped away, you get an emulator which is at least 10 times faster than the old armeabi 64bit models.&lt;/p&gt;

&lt;h1&gt;
  
  
  Isn't it too costly? 💸
&lt;/h1&gt;

&lt;p&gt;It'll definitely take investment and on-demand instances are really costly by amazon (or really any cloud provider) as far as bare metal instances are concerned, but let's really do the math.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3l55min4qgdrqyrzrtir.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3l55min4qgdrqyrzrtir.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A high performing Genymotion PaaS setup would cost you: $0.7 per emulator&lt;br&gt;
A bare metal instance at maximum load would cost you: $4.8/40 = $0.12 per emulator.&lt;/p&gt;

&lt;p&gt;See? Simple maths. To get a profitable testing fleet, you really do need to splash the cash (hence the title, solutions for an organization)&lt;/p&gt;
&lt;h1&gt;
  
  
  Soo, which system image to pick? 🤔
&lt;/h1&gt;

&lt;p&gt;I'll recommend android-28's google API version (that too x86 64-bit version) for further checking out the emulators. To get that system image, please run the following commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sdkmanager "system-images;android-28;default;x86_64"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This system image has a fairly functioning Google Apps support.&lt;/li&gt;
&lt;li&gt;Enabling root access isn't much of a pain, a simple command (adb root) would do the trick.&lt;/li&gt;
&lt;li&gt;You can play around with your emulator configurations and convert this AVD into whatever device you wish (I mean the identity, of course)&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Enabling hardware acceleration in bare metal 🏃‍♂️
&lt;/h1&gt;

&lt;p&gt;In any bare metal instance (let's say m5.metal), we need to follow the old instructions which we did so far in the first post. Now follow the following commands to set up the KVM hypervisor in ubuntu 18.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt-get install qemu-kvm libvirt-bin virtinst bridge-utils cpu-checker
$ sudo usermod --append --groups kvm 'echo $USER'
$ echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
    | sudo tee /etc/udev/rules.d/99-kvm4all.rules
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger --name-match=kvm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and this should be it. Now you can start any emulator by a simple command :&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ emulator @emulatorName
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;and this will automatically utilize KVM hypervisor to boot your emulator (PS, if you are using the system image of android-28 and x86_64 architecture, you should see your emulator booting up within 20 seconds).&lt;/p&gt;

&lt;p&gt;And this wraps us our parts on how to run fast emulators, how about, we try how to maybe install, run and uninstall apps in our emulator programmatically?&lt;/p&gt;
&lt;h1&gt;
  
  
  Setup the repository for demo 🏢
&lt;/h1&gt;

&lt;p&gt;The aim of this repository is to empower anyone to set up the emulators and try them out in order to witness the beauty (and the pain, if you have &amp;lt; 8 GB of RAM in your system) these Android emulators carry with them.&lt;/p&gt;

&lt;p&gt;Head over to Emulator CLI Autocompleter and follow the instructions in Readme to set it up!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/uds5501" rel="noopener noreferrer"&gt;
        uds5501
      &lt;/a&gt; / &lt;a href="https://github.com/uds5501/Emulator-CLI-Autocompleter" rel="noopener noreferrer"&gt;
        Emulator-CLI-Autocompleter
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Python autocomplete CLI for android emulators (Creation and APK Run demonstration)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Thanks for Reading my Blog!&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;The .zip file contains the legacy command line tools given to setup your emulator environment
To setup your emulator environment correctly, please follow the blog instructions given in either of the 2 posts&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://singhuddeshyaofficial.medium.com/deploying-android-emulators-on-aws-ec2-1-3-arm-architecture-and-genymotion-solutions-for-a-2ef3238542d5" rel="nofollow noopener noreferrer"&gt;Medium Post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/uds5501/deploying-android-emulators-on-aws-ec2-1-3-arm-architecture-and-genymotion-solutions-for-a-solo-developer-32p3" rel="nofollow"&gt;Dev.to Post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Using the emulator demo script (with autocompletion support)&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Emulator CLI is generally boring and anyone in the automation team can say amen to the fact that staring at a non saucy and tedious CLI can be a tad bit unproductive. Here is my bit to make the terminal a colourful play ground, at least, in the terms of autocompletion behaviour which is more or less non existent in the traditional command line tools provided by our dear Android team.&lt;/p&gt;
&lt;p&gt;The script uses the &lt;a href="https://github.com/prompt-toolkit/python-prompt-toolkit" rel="noopener noreferrer"&gt;prompt-toolkit&lt;/a&gt; to implement interactive CLI experience for the user. You can check out the source code in the &lt;code&gt;internal&lt;/code&gt; directory.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Requirements to run the script&lt;/h3&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/uds5501/Emulator-CLI-Autocompleter" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sdkmanager "build-tools;30.0.2"
$ export PATH=$PATH:~/path-to-built-tools/build-tools/30.0.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following CLI tool gives you an auto-completion feature in certain areas like system image picking, AVD boot, and APK choices. The repository has been created with python as the scripting tool and python-prompt as the auto-completion support.&lt;/p&gt;

&lt;p&gt;Psst… the following demonstrations have been done on an 8 GB, i7 system, So the results are at least 30–40 seconds slower than in actual systems.&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating an AVD programmatically ⚙️
&lt;/h1&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/484529556" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Here we can create an AVD programmatically using a script, currently, 3 options are provided for system images which you have to pre-install using standard SDK manager installation commands.&lt;br&gt;
The python prompt helps in selecting the SDK image you would like to pick, saving all the words you would've to type xD&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb0znea2ozmp2h60qkh1y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb0znea2ozmp2h60qkh1y.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Running an entire demo loop on created AVD 💎
&lt;/h1&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/484529596" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;br&gt;
In this particular loop, we are going to install our good old Twitter app in one of AVDs and see how smoothly it installs, runs, and finally gets uninstalled on 8 GB of host RAM.&lt;/p&gt;

&lt;p&gt;In the demonstration, it's a Twitter application, you can run any apk you want but you would need to put the APK in the apk/ directory for the prompt to load the suggestion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqzkhw90bxopaqk7p4oz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqzkhw90bxopaqk7p4oz6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above image, you can see that the tool captured 7 AVDs on the local system and proceeds to suggest the ones which match the name you are typing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx0cwqkj0mnj2f8y3p2n3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx0cwqkj0mnj2f8y3p2n3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above image, the auto-completion suggests the APK and the package name it carries, the size of the application, and release versioning.&lt;br&gt;
… and that would be the end of the demonstration ✨&lt;/p&gt;

&lt;h1&gt;
  
  
  What to expect from the next post? 🎓
&lt;/h1&gt;

&lt;p&gt;In simple bullet points&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A more robust demonstration script for easily playing around with your emulators&lt;/li&gt;
&lt;li&gt;Improvement in costing solutions and how to scale up the current solution so that it costs us 5 times cheaper but is easier to scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Resources 🔗
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/uds5501/Emulator-CLI-Autocompleter" rel="noopener noreferrer"&gt;Github CLI Autocompleter&lt;/a&gt; demonstration script&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/prompt-toolkit/python-prompt-toolkit" rel="noopener noreferrer"&gt;Python prompt&lt;/a&gt; tool kit&lt;/li&gt;
&lt;li&gt;AWS instance &lt;a href="https://aws.amazon.com/ec2/pricing/on-demand/" rel="noopener noreferrer"&gt;pricing guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
      <category>android</category>
      <category>aws</category>
      <category>cloud</category>
    </item>
    <item>
      <title>ARM architecture and Genymotion | Solutions for a solo developer</title>
      <dc:creator>Uddeshya Singh</dc:creator>
      <pubDate>Mon, 09 Nov 2020 14:46:01 +0000</pubDate>
      <link>https://dev.to/uds5501/deploying-android-emulators-on-aws-ec2-1-3-arm-architecture-and-genymotion-solutions-for-a-solo-developer-32p3</link>
      <guid>https://dev.to/uds5501/deploying-android-emulators-on-aws-ec2-1-3-arm-architecture-and-genymotion-solutions-for-a-solo-developer-32p3</guid>
      <description>&lt;p&gt;Exploring the use cases where android emulators come in handy, how to set them up on the EC2 instances, what variants you can run on cheap t2 instances, and what a solo developer should expect when planning to use AWS instances for cloud emulator deployment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--83tfTlcA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/DiO7gJEyCEDtthDn56hErImo9qrxQDJw4UNouojRogGTKC1L0b5x8HGvt8Ktm3_mIYk_X9XKOJr7BWJ6mrhrMQjNhFq0YahqL5a0%3Dw825-rw-e365-v1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--83tfTlcA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/DiO7gJEyCEDtthDn56hErImo9qrxQDJw4UNouojRogGTKC1L0b5x8HGvt8Ktm3_mIYk_X9XKOJr7BWJ6mrhrMQjNhFq0YahqL5a0%3Dw825-rw-e365-v1" alt="android user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Disclaimer: The author of this blog post documents his opinions and experiences towards android ROM and kernel in particular, anything other than that like android app development and gradle builds are not his forte and any pieces of advice will not be found under this post. Thank you for the patience, Read on!&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction and Use Cases😌
&lt;/h1&gt;

&lt;p&gt;3 Months into Trell and I have a pretty interesting project in my hand, albeit it was on the tech which was completely alien to me, the fabled android kernel, and all the complications which come with it. The task is a simple automation pipeline for application testing on multiple new devices, a purpose which android emulators can serve pretty well. But this kind of pipeline can serve multiple purposes like :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thorough testing of apps via background pipeline while not consuming your system's resources and you can carry on with your development.&lt;/li&gt;
&lt;li&gt;Testing of applications on android smartphones that you do not physically possess.&lt;/li&gt;
&lt;li&gt;Logging and Monitoring the behavior of your firebase event tags on multiple devices at once.&lt;/li&gt;
&lt;li&gt;CI/CD pipeline loves an android emulator and all your unit tests would pass through them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What is an Android Emulator? 🥧
&lt;/h1&gt;

&lt;p&gt;I am around 3 years late to this party (but definitely in sync with the time in terms of the use case) but still, let's get done with the formality and move on to the good stuff.&lt;/p&gt;

&lt;p&gt;Taking the definition directly out of Android's book, we can define the Android Emulator as a tool that simulates Android devices on your computer so that you can test your application on a variety of devices and Android API levels without needing to have each physical device.&lt;/p&gt;

&lt;p&gt;The emulator provides almost all of the capabilities of a real Android device. You can simulate incoming phone calls and text messages, specify the location of the device, simulate different network speeds, simulate rotation and other hardware sensors, access the Google Play Store, and much more.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting Up the Emulator Environment 🧑🏾‍💻
&lt;/h1&gt;

&lt;p&gt;Now, let's move on to setting up the emulator environment and the instances we would need along with it!&lt;/p&gt;

&lt;p&gt;I'll be using a classic t2.medium instance (Ubuntu 18.04, 64 bit, x86 arch) for our purpose, with adding 25 GB storage to the instance (believe me, classic 8GB won't cut it), make sure you have the authentication (.pem) key for logging into your instance and let it bootup!&lt;/p&gt;

&lt;p&gt;One important thing to note about this entire usage is that you can't access your emulator using GUI interfaces (actually, you can but that's something I have planned for some later post :P ), so we need to make sure that anything and everything we do is done solely by CLI (aka, our good old terminal!)&lt;/p&gt;

&lt;p&gt;Now, once you have logged into your t2.medium instance, you'll need to clone this repository: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/uds5501"&gt;
        uds5501
      &lt;/a&gt; / &lt;a href="https://github.com/uds5501/Emulator-CLI-Autocompleter"&gt;
        Emulator-CLI-Autocompleter
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Python autocomplete CLI for android emulators (Creation and APK Run demonstration)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
Thanks for Reading my Blog!&lt;/h1&gt;
&lt;p&gt;The .zip file contains the legacy command line tools given to setup your emulator environment
To setup your emulator environment correctly, please follow the blog instructions given in either of the 2 posts&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://singhuddeshyaofficial.medium.com/deploying-android-emulators-on-aws-ec2-1-3-arm-architecture-and-genymotion-solutions-for-a-2ef3238542d5" rel="nofollow"&gt;Medium Post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/uds5501/deploying-android-emulators-on-aws-ec2-1-3-arm-architecture-and-genymotion-solutions-for-a-solo-developer-32p3" rel="nofollow"&gt;Dev.to Post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
Using the emulator demo script (with autocompletion support)&lt;/h1&gt;
&lt;p&gt;Emulator CLI is generally boring and anyone in the automation team can say amen to the fact that staring at a non saucy and tedious CLI can be a tad bit unproductive. Here is my bit to make the terminal a colourful play ground, at least, in the terms of autocompletion behaviour which is more or less non existent in the traditional command line tools provided by our dear Android team.&lt;/p&gt;
&lt;p&gt;The script uses the &lt;a href="https://github.com/prompt-toolkit/python-prompt-toolkit"&gt;prompt-toolkit&lt;/a&gt; to implement interactive CLI experience for the user. You can check out the source code in the &lt;code&gt;internal&lt;/code&gt; directory.&lt;/p&gt;
&lt;h3&gt;
Requirements to run the script&lt;/h3&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/uds5501/Emulator-CLI-Autocompleter"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;
into your instance. This will contain your command-line tools zip file. (currently hosted version by android doesn't work for me :( )

&lt;p&gt;Now follow the commands step by step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt update &amp;amp;&amp;amp; sudo apt install default-jdk unzip -y
$ cd Emulator-Environment-Setup
$ unzip commandlinetools-linux-6609375_latest.zip
$ mkdir ../cmdline-tools
$ mv tools ../cmdline-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By now you have taken care of the basics, now we need to set the path variables (which would save us the pain of writing the entire path every time we want to call sdkmanager or emulator etc.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ nano ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now make sure your &lt;code&gt;bashrc&lt;/code&gt; file looks like&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GLY_jo8s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fso34nig32jg0lllepmo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GLY_jo8s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fso34nig32jg0lllepmo.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save this file (Ctrl + S) and get out (Ctrl + X)&lt;br&gt;
Now, load the preferences and you are good to use the SDK tools, and accept all the licenses by typing y .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ source ~/.bashrc
$ sdkmanager --licenses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You shall witness a screen like this!&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SOiW9SbT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d8rh92cnbxosw2gempfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SOiW9SbT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d8rh92cnbxosw2gempfx.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we just need to set up the emulator, platform-tools and we can create our own Android Virtual Device!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sdkmanager "emulator"
$ sdkmanager "platform-tools"
$ mkdir platforms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, your basic environment setup is done! Now let's take care of creating a virtual device.&lt;/p&gt;

&lt;h1&gt;
  
  
  Android Virtual Device on AWS 😁
&lt;/h1&gt;

&lt;p&gt;To create an AVD, you need to first select the system image it will be built on, you can list all the SDK images by typing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sdkmanager --list | grep system-images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will find multiple system images tailored to multiple devices, with a general format of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"system-images;&amp;lt;version&amp;gt;;&amp;lt;gapi_setting&amp;gt;;&amp;lt;emulator_architecture&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take a look at the given configurations, they are all of android-25 (Nougat) and come in variants of android_tv, default,  google_apis etc, with 2 architectures namely ARM and Intel's x86 which further bifurcates into 32 bit and 64-bit variants.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Sh__UaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fiez67z36a3ecqv9h1ld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Sh__UaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fiez67z36a3ecqv9h1ld.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But we will specifically be using system-images;android-25;google_apis;armeabi-v7a version. Now let me justify this choice.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why android-25? 🤔
&lt;/h3&gt;

&lt;p&gt;This is something which Trell needed for checking firebase event logging, anything less than android-29, so picking a decently lower version made sense to observe backward portability of the app.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why the google_api version? 🙇🏽‍♂️
&lt;/h3&gt;

&lt;p&gt;We can perform a wide variety of operations on our android emulator if they are rooted by default (we have the superuser access). To connect into root mode and access emulator shell using the command line, we need this version to be "default" because google_apis and google_apis_playstore won't allow root connection from the android debugging bridge (in intel architectures) but in ARM (like this one) you can take anyone, all will be rooted by default!&lt;/p&gt;
&lt;h3&gt;
  
  
  Why armeabi-v7a architecture? 💁🏾‍♂️️
&lt;/h3&gt;

&lt;p&gt;v7a represents a 32-bit version of the ARMarchitect architecture (something which is required for the trell app). Now, why ARM? because Intel (x86) architecture requires hardware acceleration to work, and this can be done with either Intel HAXM (in windows) or KVM (in Ubuntu). You can try this sequence of commands to check if KVM can be enabled on your instance or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo apt install cpu-checker -y
$ kvm-ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would greet you with the following message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;INFO: Your CPU does not support KVM extensions
INFO: For more detailed results, you should run this as root
HINT:   sudo /usr/sbin/kvm-ok
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Why do intel emulators not work in these EC2 instances? 😭
&lt;/h1&gt;

&lt;p&gt;Before we get into this, let's take a quick look at how emulators work. QEMU is a tool that mimics guest device hardware and it then translates the Application Binary Interface (ABI) of the guest device to match that of the host device.(armeabi-v7a to intel x86_64 in this case). Now to speed up this complex and slow process, hypervisors are introduced.&lt;/p&gt;

&lt;p&gt;Intel's HAXM (Hardware Acceleration Execution Manager) is a hypervisor component for Windows and macOS. There's KVM (Kernel-based Virtual Machine) for Linux. With hardware-acceleration, the Android emulator can run virtual devices at speeds similar to that of your workstation CPU.&lt;/p&gt;

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

&lt;p&gt;When we choose system-images;android-25;default;x86 we are trying to run a virtual machine within a virtual machine. It is a second level or nested virtualization that we are trying to achieve which, unfortunately, is not yet supported. The Intel hardware supports only a single level of hardware-assisted virtualization, adding support for efficient (i.e., not painfully slow) nesting requires a lot of clever software engineering in hypervisors. &lt;/p&gt;

&lt;h1&gt;
  
  
  Run a Testing Device 🏃🏽‍♂️
&lt;/h1&gt;

&lt;p&gt;All the theory currently stated as to what will and what won't work, let's focus on creating a test virtual device. Follow the steps to do so!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sdkmanager "system-images;android-25;google_apis;armeabi-v7a"
$ echo "no" | avdmanager create avd --name "testDevice" -k "system-images;android-25;google_apis;armeabi-v7a"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, you just created an AVD, how to check that out? You can use &lt;code&gt;avdmanager&lt;/code&gt; to check your virtual android devices.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ avdmanager list avd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's run this virtual device!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ emulator -ports 5554,5555 -avd testDevice -writable-system -no-window -no-audio -gpu swiftshader_indirect -show-kernel &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-ports 5554,5555&lt;/code&gt; define the connection ports on which the android debug bridge will connect to this emulator (in this case, 5554) and they have to be consecutive!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-writable-system&lt;/code&gt; would give you access to modify any file or push any file as you wish in root settings.'&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-no-window&lt;/code&gt; would simply run the emulator headless (without this flag, it won't work because we don't have any OpenGL based graphics setup on a CLI)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-no-audio&lt;/code&gt; would take away it's audio support (something I'd suggest you do)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-gpu swiftshader_indirect&lt;/code&gt; to prevent a boot loop.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-show-kernel&lt;/code&gt; something for you to maintain your sanity and check the kernel's progress as it boots up because it WILL take forever (60–90 minutes) to boot up properly.&lt;/p&gt;

&lt;p&gt;These are the testimonials on why you should not go for something this slow, because this would be counterproductive, you can rather test on your local devices rather on a device which will take 1 hour to function properly and still give you an average of 2.5 minutes to install a normal apk!&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Genymotion and how good is it? 📱
&lt;/h1&gt;

&lt;p&gt;If you are a solo developer and can afford the Genymotion PaaS subscription ($0.5 + amazon instance charges), it's your way to go. For example, I am using m4.xlarge with Genymotion PaaS on top, it'll cost you $0.7/hr and it will be a decent deal if you can afford it.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://player.vimeo.com/video/476891197" width="710" height="399"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Genymotion is a go-to emulator for many organizations still and the amazing support and speed which their emulators provide are good enough for the purpose we want to solve, if and only if, your pocket allows you that much freedom.&lt;/p&gt;

&lt;p&gt;But, still, $0.7/hr per emulator is a bit too costly, at least if you wanna do testing on a large scale.&lt;/p&gt;

&lt;h1&gt;
  
  
  Closing Thoughts and what to expect from the upcoming post? 👨🏽‍🏫
&lt;/h1&gt;

&lt;p&gt;In this post, we explored the basic setup of an emulator environment and how to setup a simple AVD. What works in a general t2 instance and what are the alternatives.&lt;/p&gt;

&lt;p&gt;In the next one, we'll explore how to setup multiple emulators in a single instance and explore android debug bridge in depth while customizing our device and run simple applications with intel emulators (which are at least 10x faster than these ones)!&lt;/p&gt;

&lt;h1&gt;
  
  
  References 🔗
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/studio/run/emulator"&gt;Official Android Emulator Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/atyachin/cf1690085173e1fabc07b9acc7af3de6"&gt;Atyachin's Gist on Environment Setup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.browserstack.com/android-emulators#how-do-android-emulators-work"&gt;How do emulators work?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/47544211/kvm-not-working-with-ec2-c5-large/48742008#48742008"&gt;Nested virtualization not working in EC2 instance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>showdev</category>
      <category>android</category>
      <category>aws</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Go-Arch | Module Scripting Bootstrap in Go Lang</title>
      <dc:creator>Uddeshya Singh</dc:creator>
      <pubDate>Fri, 23 Oct 2020 06:50:05 +0000</pubDate>
      <link>https://dev.to/uds5501/go-arch-module-scripting-bootstrap-in-go-lang-37cj</link>
      <guid>https://dev.to/uds5501/go-arch-module-scripting-bootstrap-in-go-lang-37cj</guid>
      <description>&lt;h3&gt;
  
  
  Introduction 📖
&lt;/h3&gt;

&lt;p&gt;Two months into my internship at &lt;a href="https://trell.co.in/" rel="noopener noreferrer"&gt;Trell&lt;/a&gt; - A Visual Blogging Platform for Explorers! as a full stack developer, I dived headfirst into the world of Go and more specifically the Gin Web framework. Upon my first major project assignment, I was given this holy grail module, a one-stop solution for any scripting + HTTP server requirements including integrations with SQL database, Redis and Elastic. We Majorly used this for scripting and I will be elaborating how.&lt;/p&gt;

&lt;h3&gt;
  
  
  TL; DR 🚶‍♂️
&lt;/h3&gt;

&lt;p&gt;If you know the basics of scripting and how the module works in go lang and just want a bootstrap code for getting started with the scripting part, head over to this GitHub repository &lt;a href="https://github.com/uds5501/go-arch" rel="noopener noreferrer"&gt;uds5501/go-arch&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Case 💡
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This module can be used interchangeably whenever you need a web server or a script.&lt;/li&gt;
&lt;li&gt;You can use this to create a database scheduled task dequeuer (Which we did)&lt;/li&gt;
&lt;li&gt;This can be used for a custom task queue in coupling with Redis (check this post maybe: &lt;a href="https://medium.com/@mhewedy_46874/implement-job-queue-in-redis-9f0f8d394561" rel="noopener noreferrer"&gt;Implement Job queue in Redis&lt;/a&gt;[0]&lt;/li&gt;
&lt;li&gt;You can couple this with &lt;a href="https://github.com/olivere/elastic" rel="noopener noreferrer"&gt;go-Olivere&lt;/a&gt; [1] package to integrate ELK Stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, we can get right into our project structure!&lt;/p&gt;

&lt;h3&gt;
  
  
  What is go-arch and what are we building? 👨🏻‍💻
&lt;/h3&gt;

&lt;p&gt;Go-arch is a small module that employs multiple packages and the goal work of the script is to do simple hardcoded arithmetic operations.&lt;/p&gt;

&lt;p&gt;It is a condensed version of the project implementation we actually did at Trell, that project employs Redis, elastic, and Kubernetes (for deployment) but what I will be showing is scaled-down version with only a database and logging module, while the main Module (Operations) will be taking care of only &lt;strong&gt;simple arithmetic operations&lt;/strong&gt; (+,-,* to be specific) and structural outlines and what method in which package calls what struct in which package.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Structure (For Scripts) 🔧
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;rookie mistake&lt;/strong&gt; of a hackathon project in Go is to bundle everything you want to do into a simple main.go and completely forget about it, until next time you change a single line of logs and bam! Your IDE is full of yellow and red lines to check where did we go wrong.&lt;br&gt;
Now bundling around 5k lines of code was an option to me, but making your first Go project in a monolith directory layout? That should prick your conscience. &lt;br&gt;
So here is a much more distributed layout and a scaled-down version of the boilerplate we actually use!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdpvztcxlgt01mg3icm4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdpvztcxlgt01mg3icm4p.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  Package definition
&lt;/h5&gt;

&lt;p&gt;&lt;strong&gt;config :&lt;/strong&gt; Takes care of the project setup, this is where we read our environment files and return a &lt;code&gt;config&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;db :&lt;/strong&gt; As the name suggests, takes care of the database connection handler for our project and returns a db handler for the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;logger :&lt;/strong&gt; This package helps in logging errors and debugging messages at production and development level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pkg/common :&lt;/strong&gt; Here we build our utility functions which are supposed to be accessible for trivial operations in our main script aka &lt;code&gt;checkAdder.go&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pkg/scripts :&lt;/strong&gt; This is the money shot. This is where your main script should be placed and your &lt;code&gt;server.go&lt;/code&gt; should take all the scripting logic it wants from right here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;redis :&lt;/strong&gt; Again as the name suggests, for handling local redis connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;server :&lt;/strong&gt; The layer between &lt;code&gt;main.go&lt;/code&gt; and your business logic ( &lt;code&gt;pkg/scripts&lt;/code&gt;). Here you can decide whether you want your package to be a gin web server or a simple script hosting module, it's all your choice!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;main.go :&lt;/strong&gt; This bad boy seriously does not need any introductions!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;go.mod :&lt;/strong&gt; Stores your external dependencies and it is what stores the module dependencies which are required for a successful run.&lt;/p&gt;

&lt;p&gt;Now that our layout is defined, let's go step by step to our package setup!&lt;/p&gt;
&lt;h3&gt;
  
  
  [1/8] Basic Environment Configuration 🔧
&lt;/h3&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;config&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;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/joho/godotenv"&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;Config&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;AppName&lt;/span&gt;              &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;AppEnv&lt;/span&gt;               &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;SqlPrefix&lt;/span&gt;            &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;RedisAddr&lt;/span&gt;            &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBUserName&lt;/span&gt;           &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBPassword&lt;/span&gt;           &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBHostWriter&lt;/span&gt;         &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBHostReader&lt;/span&gt;         &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBPort&lt;/span&gt;               &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBName&lt;/span&gt;               &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBMaxOpenConnections&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;DBMaxIdleConnections&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;ServerPort&lt;/span&gt;           &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;EsURL&lt;/span&gt;                &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;EsPort&lt;/span&gt;               &lt;span class="kt"&gt;int&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;config&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;

&lt;span class="c"&gt;// Should run at the very beginning, before any other package&lt;/span&gt;
&lt;span class="c"&gt;// or code.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;appEnv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"APP_ENV"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appEnv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&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;appEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dev"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;configFilePath&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;".env"&lt;/span&gt;

    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;appEnv&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"production"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;configFilePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;".env.prod"&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"stage"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;configFilePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;".env.stage"&lt;/span&gt;
        &lt;span class="k"&gt;break&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;"reading env from: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;configFilePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;godotenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configFilePath&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;e&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;"error loading env: "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ELASTIC_APM_SERVICE_NAME"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppEnv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;appEnv&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SqlPrefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/* "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" - "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppEnv&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"*/"&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RedisAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"REDIS_ADDR"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBUserName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_USERNAME"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBHostReader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_HOST_READER"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBHostWriter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_HOST_WRITER"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReplaceAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_PASSWORD"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"--"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_NAME"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBMaxIdleConnections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_MAX_IDLE_CONENCTION"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBMaxOpenConnections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DB_MAX_OPEN_CONNECTIONS"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SERVER_PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EsURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ES_URL"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EsPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ES_PORT"&lt;/span&gt;&lt;span class="p"&gt;))&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;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;Config&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;config&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;IsProduction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&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;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppEnv&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"production"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;We use a config structure to grab all the configuration parameters from &lt;code&gt;.env&lt;/code&gt; file us godotenv and return the struct object for further use. You can configure which env file to use according to the &lt;code&gt;APP_ENV&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;h3&gt;
  
  
  [2/8] Setup the database handler ⛓
&lt;/h3&gt;

&lt;p&gt;Though this is not really required for what I will be building, but this is still a handy exercise to see how you can seemlessly pass around a configured database module into business modules without any re-initialisation.&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;db&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;"database/sql"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;

    &lt;span class="s"&gt;"trell/go-arch/config"&lt;/span&gt;

    &lt;span class="s"&gt;"trell/go-arch/logger"&lt;/span&gt;

    &lt;span class="s"&gt;"go.elastic.co/apm/module/apmsql"&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="s"&gt;"go.elastic.co/apm/module/apmsql/mysql"&lt;/span&gt;
    &lt;span class="s"&gt;"go.uber.org/zap"&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;reader&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;once&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;Once&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;DBConfig&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;DBUserName&lt;/span&gt;           &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBPassword&lt;/span&gt;           &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBHost&lt;/span&gt;               &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBPort&lt;/span&gt;               &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBName&lt;/span&gt;               &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;DBMaxIdleConnections&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;DBMaxOpenConnections&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;DBConnMaxLifetime&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewDBClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DBConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&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="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBUserName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBPassword&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"@tcp("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"trell-mysql-db-staging.cyqwbanzexpw.ap-south-1.rds.amazonaws.com"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBPort&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;")/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"?multiStatements=true&amp;amp;parseTime=true"&lt;/span&gt;
    &lt;span class="n"&gt;client&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;apmsql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mysql"&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;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="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetMaxIdleConns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBMaxIdleConnections&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetMaxOpenConns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBMaxOpenConnections&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetConnMaxLifetime&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;Minute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;10&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;client&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;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;once&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;config&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;writerConfig&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;DBConfig&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;DBUserName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;           &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBUserName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;DBPassword&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;           &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;DBHost&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;               &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBHostWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;DBPort&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;               &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;DBName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;               &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;DBMaxIdleConnections&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBMaxIdleConnections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;DBMaxOpenConnections&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBMaxOpenConnections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;DBConnMaxLifetime&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;Minute&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;readerConfig&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;writerConfig&lt;/span&gt;
        &lt;span class="n"&gt;readerConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBHostReader&lt;/span&gt;

        &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NewDBClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readerConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NewDBClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writerConfig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"writer connected"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBHostReader&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"reader connected"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBHostWriter&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typ&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;typ&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"reader"&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;reader&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"writer"&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;writer&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"no such db"&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;WrapQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;config&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SqlPrefix&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;query&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;DBFactory&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;t&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Over here, we reuse the config module's struct and use our own DBConfig struct to setup the database connection handler. You can see that there is a nice combination of &lt;code&gt;database/sql&lt;/code&gt; and &lt;code&gt;ampsql&lt;/code&gt; packages to handle the database connection.&lt;/p&gt;

&lt;h5&gt;
  
  
  What are readers and writers? 🤔
&lt;/h5&gt;

&lt;p&gt;&lt;strong&gt;Writer Handler&lt;/strong&gt; handles write heavy queries (like inserting, batch insertion and updating) into a database and the &lt;strong&gt;Reader handles&lt;/strong&gt; the select queries from the database. Although, this is for elastic search and not vanilla sql so you can really skip it.&lt;/p&gt;

&lt;h3&gt;
  
  
  [3/8] Setup the Logger 🧾
&lt;/h3&gt;

&lt;p&gt;With the database setup, now let's take care of how we are going to show you, the developer the outputs because we firmly need dubgging module in place for production environment. You can get away with a series of &lt;code&gt;fmt.Println()&lt;/code&gt; but it won't really cut it in a production environment.&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;logger&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="s"&gt;"trell/go-arch/config"&lt;/span&gt;

    &lt;span class="s"&gt;"go.uber.org/zap"&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;logger&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;once&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;Once&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;once&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&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="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsProduction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewProduction&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;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDevelopment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sync&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&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;logger&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;At trell, we are using Uber's zap logger and it's fast. No, really fast when it comes to logging. Don't believe me? Check this &lt;a href="https://github.com/uber-go/zap#performance" rel="noopener noreferrer"&gt;performance comparison&lt;/a&gt;[2] and see for yourself!&lt;/p&gt;

&lt;h3&gt;
  
  
  [4/8] Implementing the Operations Script Logic ✨
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;pkg/scripts&lt;/code&gt; let's make our checkAdder.go which will be a part of &lt;code&gt;scripts&lt;/code&gt; package. Just create a struct named Operations which will be the initialized script.&lt;br&gt;
It will contain a DB factory struct export (from &lt;code&gt;trell/go-arch/db&lt;/code&gt; package) and define the methods accordingly.&lt;/p&gt;

&lt;h5&gt;
  
  
  Exportable and private methods ✨
&lt;/h5&gt;

&lt;p&gt;I have created &lt;code&gt;Init()&lt;/code&gt; and &lt;code&gt;ExportableFunction()&lt;/code&gt; as an example. These functions are named in a capitalized manner and these are the ones that can be accessed by default when you call utility functions inside another script.&lt;/p&gt;

&lt;p&gt;The functions like &lt;code&gt;getAddition()&lt;/code&gt;, &lt;code&gt;getSubtraction()&lt;/code&gt; etc are non capitalized and are in camel-case, they can be accessed within the struct but not outside it.&lt;/p&gt;

&lt;h5&gt;
  
  
  What does NewOperations() do? 🤔
&lt;/h5&gt;

&lt;p&gt;The sole purpose of existence of this capitalized function is to initialize a new Operations script in &lt;code&gt;module.go&lt;/code&gt; which in turn can be used for almost any operation (in our case, Initialization only)&lt;/p&gt;

&lt;h3&gt;
  
  
  [5/8] Making sure the script is initialized only Once 🙇🏻‍♂️
&lt;/h3&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;scripts&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="s"&gt;"trell/go-arch/db"&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;Module&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;script&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Operations&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;moduleSingleton&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;moduleSingletonOnce&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;Once&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewScriptsModuleSingleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DBFactory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;moduleSingletonOnce&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewOperation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;moduleSingleton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;script&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;moduleSingleton&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;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetScript&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Operations&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;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;To make sure we initialize the script only once for our application, we will use the function &lt;code&gt;NewScriptsModuleSingleton()&lt;/code&gt; to call an instance of &lt;code&gt;sync.Once&lt;/code&gt; (which executes a function once) and return a struct with Operations module pointer.&lt;/p&gt;

&lt;p&gt;Ps: you should really read more about context management and process syncing to get the idea behind &lt;code&gt;sync.Once()&lt;/code&gt; from the official docs or &lt;a href="https://medium.com/@matryer/sync-once-with-reset-in-golang-quicktip-6ac44b015256" rel="noopener noreferrer"&gt;this&lt;/a&gt;.[3]&lt;/p&gt;

&lt;p&gt;You will be executing &lt;code&gt;GetScript()&lt;/code&gt; to get this script with appropriate definitions inside your infinite running code (in this case, &lt;code&gt;server.go&lt;/code&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  [6/8] Setup the server 🖥
&lt;/h3&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;server&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;"trell/go-arch/db"&lt;/span&gt;
    &lt;span class="s"&gt;"trell/go-arch/logger"&lt;/span&gt;
    &lt;span class="s"&gt;"trell/go-arch/pkg/scripts"&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;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c"&gt;//es.Init()&lt;/span&gt;
    &lt;span class="c"&gt;//redis.Init()&lt;/span&gt;
    &lt;span class="n"&gt;scriptsModule&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;scripts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewScriptsModuleSingleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;scriptsModule&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetScript&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c"&gt;// r := NewRouter()&lt;/span&gt;
    &lt;span class="c"&gt;// r.Run(":" + "4000")&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 simple initialzation of a server. It initializes the logger and database and once that's done, It calls for the &lt;strong&gt;scriptsModule&lt;/strong&gt; to initialize the business logic scripts (in this case, our &lt;code&gt;pkg/scripts/module.go&lt;/code&gt; will be called) and will run infinitely.&lt;/p&gt;

&lt;h3&gt;
  
  
  [7/8] Last but not the least, main.go 🌠
&lt;/h3&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="n"&gt;_&lt;/span&gt; &lt;span class="s"&gt;"trell/go-arch/config"&lt;/span&gt;
    &lt;span class="s"&gt;"trell/go-arch/server"&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;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Init&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 it, that's all, just call server.Init() rest will be a series of procedural calls as shown in the diagram below and to run your app, use &lt;code&gt;go run main.go&lt;/code&gt; and see the magic!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyyikynohvd6is5g8bokg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyyikynohvd6is5g8bokg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  [8/8] One more thing, external modules? 🤦
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;go run main.go&lt;/code&gt; didn't work? oops, one last thing. So far we have taken care of modules which we defined ourselves, but what about the modules we have been using externally? (like go-redis, ampsql etc). Use &lt;code&gt;go.mod&lt;/code&gt; file for that, as this is what really makes your &lt;strong&gt;go-arch a module&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's basically like package.json, where you specify the external dependencies and versions of the same and on each build which are required for a successful build of your own go module, a &lt;code&gt;go.sum&lt;/code&gt; file will be created, storing their hashes for future use, just like package.lock.&lt;/p&gt;

&lt;p&gt;And that's a wrap, This makes sure that your go module is packaged and runs perfectly on each successful build, go ahead and give it a try now. The Github repository link can be found here &lt;a href="https://github.com/uds5501/go-arch" rel="noopener noreferrer"&gt;&lt;strong&gt;uds5501/go-arch&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Links Provided 🗣
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[0]Job Queues: &lt;a href="https://medium.com/@mhewedy_46874/implement-job-queue-in-redis-9f0f8d394561" rel="noopener noreferrer"&gt;@mhewedy's post&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[1] Go-Olivere : &lt;a href="https://github.com/olivere/elastic" rel="noopener noreferrer"&gt;Go-Olivere docs &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[2] Go-Zap : &lt;a href="https://github.com/uber-go/zap#performance" rel="noopener noreferrer"&gt;Go Zap performance&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[3] Sync.Once : &lt;a href="https://medium.com/@matryer/sync-once-with-reset-in-golang-quicktip-6ac44b015256" rel="noopener noreferrer"&gt;@martyer's post&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>go</category>
      <category>scripting</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
