<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Altiano Gerung</title>
    <description>The latest articles on Forem by Altiano Gerung (@altiano).</description>
    <link>https://forem.com/altiano</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%2F78508%2F20994564-8486-4480-8cdf-2d0d9e29337d.jpeg</url>
      <title>Forem: Altiano Gerung</title>
      <link>https://forem.com/altiano</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/altiano"/>
    <language>en</language>
    <item>
      <title>Cnator: channel-based subscriptions in Go</title>
      <dc:creator>Altiano Gerung</dc:creator>
      <pubDate>Wed, 26 May 2021 16:17:03 +0000</pubDate>
      <link>https://forem.com/altiano/cnator-channel-based-subscriptions-in-go-4een</link>
      <guid>https://forem.com/altiano/cnator-channel-based-subscriptions-in-go-4een</guid>
      <description>&lt;p&gt;Channels is one of those things that makes Go awesome.&lt;/p&gt;

&lt;p&gt;I use channels quite a lot in my next open projects. One of those scenario is to model an event-driven approach.&lt;/p&gt;

&lt;p&gt;While developing these projects, I noticed that the setup is more or less the same, so I decided to make a Go module for that.&lt;/p&gt;

&lt;p&gt;It's called &lt;a href="https://gitlab.com/altiano/cnator"&gt;&lt;code&gt;Cnator&lt;/code&gt;&lt;/a&gt; (pronounce "c-nator")&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;gitlab&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;altiano&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cnator&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It has 3 methods : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;New()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Subscribe(channel, subscriber)&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;Serve()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;that can be use it like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="n"&gt;cnator&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cnator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;channels&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;createChannels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// provide channel reference to each publisher&lt;/span&gt;
    &lt;span class="n"&gt;producerA&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewProducerA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chanA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;producerB&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewProducerB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chanB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;producerC&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewProducerC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chanC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// using cnator to subscribe to those channel events&lt;/span&gt;
    &lt;span class="n"&gt;subscriberA&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;subscriberA&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;subscriberB&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;subscriberB&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;subscriberC&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;subscriberC&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;cnator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chanA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subscriberA&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;receiveChanA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cnator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chanB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subscriberB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;receiveChanB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cnator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channels&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chanC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subscriberC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;receiveChanC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

     &lt;span class="c"&gt;// start watching for events&lt;/span&gt;
    &lt;span class="n"&gt;cnator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;createChannel()&lt;/code&gt; just initialized the channels, but you should provide your own model&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createChannels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;channels&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;channels&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;chanA&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}),&lt;/span&gt;
        &lt;span class="n"&gt;chanB&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;chanC&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the subscribers are just callback functions with a matching data type with the channels&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;subscriberA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;receiveChanA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Subscriber A receiving"&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;subscriberB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;receiveChanB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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;"Subscriber B receiving"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;subscriberC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;receiveChanC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Subscriber C receiving"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&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;except for &lt;code&gt;chanA&lt;/code&gt; that receive empty struct{}, &lt;br&gt;
you can ignore the parameter like &lt;code&gt;receiveChanA()&lt;/code&gt; does.&lt;/p&gt;

&lt;p&gt;The job of &lt;code&gt;cnator.Serve()&lt;/code&gt; is to spawn a go routine for each subscription made by &lt;code&gt;cnator.Subscribe(..)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It provides some runtime validation like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whether the subscriber function doesn't satisfy the channel data type or &lt;/li&gt;
&lt;li&gt;whether the channel has not been initialized (i.e. forget to &lt;code&gt;make(chan ..)&lt;/code&gt;) etc &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full code &amp;amp; examples can be found at this repository : &lt;a href="https://gitlab.com/altiano/cnator"&gt;Cnator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Also posted on : &lt;a href="https://blog.altiano.dev/cnator-channel-based-subscription-in-go"&gt;https://blog.altiano.dev/cnator-channel-based-subscription-in-go&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>opensource</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>Goreen tea : golang boilerplate for data-intensive microservice</title>
      <dc:creator>Altiano Gerung</dc:creator>
      <pubDate>Tue, 11 May 2021 07:38:32 +0000</pubDate>
      <link>https://forem.com/altiano/goreen-tea-golang-boilerplate-for-data-intensive-microservice-14j9</link>
      <guid>https://forem.com/altiano/goreen-tea-golang-boilerplate-for-data-intensive-microservice-14j9</guid>
      <description>&lt;p&gt;First of all, I am super thrilled to announce my very first open source project. (#🔥) &lt;br&gt;
This is just the beginning, and I'm planning to be more involved in &lt;br&gt;
open source projects at least in the next couple of months.&lt;/p&gt;

&lt;p&gt;So, without further ado, &lt;br&gt;
I introduce you to &lt;a href="https://gitlab.com/altiano/goreen-tea" rel="noopener noreferrer"&gt;&lt;strong&gt;Goreen-tea&lt;/strong&gt;&lt;/a&gt; 🍵 &lt;br&gt;
A boilerplate project that focused on data-intensive (database heavy) microservice. &lt;br&gt;
Heavily inspired around the idea of application-centric architecture like &lt;a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html" rel="noopener noreferrer"&gt;clean architecture&lt;/a&gt; by Robert Martin.&lt;/p&gt;

&lt;p&gt;Clone it and setup a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://gitlab.com/altiano/goreen-tea.git &lt;span class="nt"&gt;--depth&lt;/span&gt; 1
&lt;span class="nb"&gt;cd &lt;/span&gt;goreen-tea
bash ./init.sh &amp;lt;base-url&amp;gt; &amp;lt;project-name&amp;gt;
&lt;span class="c"&gt;# e.g. bash ./init.sh gitlab.com/altiano awesomeness-api&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Goal
&lt;/h2&gt;

&lt;p&gt;My goal is to quickly jump into the project requirements, &lt;br&gt;
without having to spend much time to setup the same old thing over and over again. &lt;br&gt;
It is to be more productive.&lt;/p&gt;

&lt;p&gt;The boilerplate should be very &lt;strong&gt;simple&lt;/strong&gt;, &lt;br&gt;
packed with some &lt;strong&gt;modern best practices&lt;/strong&gt; &lt;br&gt;
and of course quite &lt;strong&gt;flexible&lt;/strong&gt; for changes in the future as new technologies arrived.&lt;/p&gt;
&lt;h2&gt;
  
  
  Restaurant order sample
&lt;/h2&gt;

&lt;p&gt;I already set up a sample scenario of kinda like my expectation of being productive of using this project. It is about ordering system in a restaurant.&lt;/p&gt;

&lt;p&gt;The requirement are as follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It should be able to record a customer order (CO), which has following specs

&lt;ul&gt;
&lt;li&gt;Who they are (for the sake of simplicity, we'll use the customer email).&lt;/li&gt;
&lt;li&gt;What they order, at least one.&lt;/li&gt;
&lt;li&gt;From whom the they heard about the restaurant, we'll use referral code.&lt;/li&gt;
&lt;li&gt;What will be their own referral code to give to the other.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It also should be able to assigned the waiter for an order.

&lt;ul&gt;
&lt;li&gt;Depending of how "valuable" the order is and the waiters availability,
It may be assigned a waiter with higher rating.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The customer that give their referral code will be notified via email when it is used.&lt;/li&gt;
&lt;li&gt;It would be nice if the restaurant knows the number of customers.&lt;/li&gt;
&lt;/ul&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%2Fblog.altiano.dev%2Fgoreen-tea-introduction%2Frestaurant-order-sample.jpg" 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%2Fblog.altiano.dev%2Fgoreen-tea-introduction%2Frestaurant-order-sample.jpg" title="restaurant order diagram" alt="restaurant order diagram"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  App package implementation
&lt;/h3&gt;

&lt;p&gt;Here I define that all the above requirements will happen in a one go. &lt;br&gt;
So we give it a name : &lt;code&gt;onsiteOrder.go&lt;/code&gt; in the app package.&lt;/p&gt;

&lt;p&gt;The four major steps are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The creation of CO record &lt;strong&gt;(A)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The waiter selection to serve the order &lt;strong&gt;(B)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Referral code notification &lt;strong&gt;(C)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Live tracking stats &lt;strong&gt;(D)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I put a label at the end so that we can see the relation of each step with the domain that is responsible for a more detailed implementation.&lt;/p&gt;
&lt;h3&gt;
  
  
  Domain package implementation
&lt;/h3&gt;

&lt;p&gt;Then, I define the domain package as below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CustomerOrder&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;will be responsible to create CO record and generate its own referral code &lt;strong&gt;(A)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;notify the referral code owner via email &lt;strong&gt;(C)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;notify a customer who will be their waiter &lt;strong&gt;(B)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Waiter&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Pick a top waiter currently available &lt;strong&gt;(B)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;or to pick a normal waiter &lt;strong&gt;(B)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;and able to increase the total serve of a waiter if they are chosen &lt;strong&gt;(B)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AssistanceCordinator&lt;/code&gt;
A domain doesn't necessarily mean a real business entity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There may be times that you need to perform cross-domain calls as a single operation, meaning it would result in an inconsistent state if one call success the the other failed. &lt;br&gt;
  Think of it kinda like a transaction.&lt;/p&gt;

&lt;p&gt;Here I define an auxiliary domain that responsible for waiter assignment. &lt;br&gt;
  This domain will depends on the &lt;code&gt;CustomerOrder&lt;/code&gt; &amp;amp; &lt;code&gt;Waiter&lt;/code&gt; &lt;strong&gt;(B)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;VisitorCounter&lt;/code&gt; (what do think? 🤷‍♂️)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, I highly suggest you to look at the sample code so that it will become clearer.&lt;/p&gt;
&lt;h3&gt;
  
  
  Running the project
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;The example use &lt;strong&gt;MongoDB&lt;/strong&gt; as its database (I like MongoDB). 
If you happen to have docker running and haven't install MongoDB yet, 
you can use the &lt;code&gt;docker-compose.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I already setup a sample waiter list, just run &lt;code&gt;.misc/mongo-playground/seed_waiters.js&lt;/code&gt; in your MongoDB shell.&lt;/li&gt;
&lt;li&gt;In it, there is also &lt;strong&gt;Jaeger&lt;/strong&gt; as the tracing backend but it is optional. 
If you never used some kind of tracing, I would highly recommended you learn a little bit more about jaeger. 
Tracing itself is an important part when you project goes live.&lt;/li&gt;
&lt;li&gt;You should also have &lt;code&gt;.env&lt;/code&gt; file in the project root directory like this:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;APP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8888&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;which&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt;
&lt;span class="nx"&gt;MONGO_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;mongodb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:27017 # your mongodb connection-string&lt;/span&gt;
&lt;span class="nx"&gt;MONGO_DB_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;boilerplate&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;mongdob&lt;/span&gt; &lt;span class="nx"&gt;collection&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="nx"&gt;JEAGER_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:14268/api/traces # Optional if jaeger not present&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Run it with &lt;code&gt;go run main.go&lt;/code&gt; ,&lt;br&gt;
Try it with http request like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;POST&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//localhost:8888/customerOrder&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;satoshi@domain.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Orders&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;satay&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fried rice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;meatball&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;green tea&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ReferralCode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// indicates satoshi not use any referral code &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Core architecture
&lt;/h3&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%2Fblog.altiano.dev%2Fgoreen-tea-introduction%2Farchitecture.jpg" 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%2Fblog.altiano.dev%2Fgoreen-tea-introduction%2Farchitecture.jpg" title="goreen tea architecture" alt="goreen tea architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A peek at what inside.. 🔭
&lt;/h2&gt;

&lt;p&gt;Some of the features that I haven't mention yet are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit testing with &lt;a href="https://github.com/golang/mock" rel="noopener noreferrer"&gt;go-mock&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dependency injection with &lt;a href="https://github.com/google/wire" rel="noopener noreferrer"&gt;google wire&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;VS code snippets, tasks and postman-like http testing&lt;/li&gt;
&lt;li&gt;Dockerfile&lt;/li&gt;
&lt;li&gt;K8S manifest&lt;/li&gt;
&lt;li&gt;GitLab CI&lt;/li&gt;
&lt;li&gt;Open telemetry with jaeger&lt;/li&gt;
&lt;li&gt;Rest API with iris&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To describe them one by one would be really time consuming. &lt;br&gt;
And it is not the purpose of this introduction article either. &lt;br&gt;
See them for yourself, and feel free to ask question to me, directly, anytime. &lt;/p&gt;

&lt;h2&gt;
  
  
  So, looking forward.. 🌄
&lt;/h2&gt;

&lt;p&gt;I'd like to include these features in the next release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data store

&lt;ul&gt;
&lt;li&gt;MongoDB seeding&lt;/li&gt;
&lt;li&gt;MySQL support&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Servers

&lt;ul&gt;
&lt;li&gt;GRPC&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Messaging

&lt;ul&gt;
&lt;li&gt;Kafka&lt;/li&gt;
&lt;li&gt;NATS&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As I said in the beginning, &lt;br&gt;
this is just the &lt;em&gt;beginning&lt;/em&gt;, &lt;br&gt;
I'd love to hear some &lt;strong&gt;feedbacks&lt;/strong&gt; to improve this project. &lt;/p&gt;

&lt;p&gt;Thank you for your time.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Original posted on : &lt;a href="https://blog.altiano.dev/goreen-tea-introduction/" rel="noopener noreferrer"&gt;https://blog.altiano.dev/goreen-tea-introduction/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>microservices</category>
      <category>mongodb</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
