<?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: Jan Stamer</title>
    <description>The latest articles on DEV Community by Jan Stamer (@remast).</description>
    <link>https://dev.to/remast</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%2F174171%2F820e2c45-8713-4e15-be64-84b5cc140799.jpeg</url>
      <title>DEV Community: Jan Stamer</title>
      <link>https://dev.to/remast</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/remast"/>
    <language>en</language>
    <item>
      <title>The DDD Hamburger for Go</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Sat, 06 Jan 2024 19:05:46 +0000</pubDate>
      <link>https://dev.to/remast/the-ddd-hamburger-for-go-2156</link>
      <guid>https://dev.to/remast/the-ddd-hamburger-for-go-2156</guid>
      <description>&lt;p&gt;The DDD Hamburger is my favorite type of architecture for Go. Why? The DDD Hamburger beautifully combines the best of the &lt;a href="https://alistair.cockburn.us/hexagonal-architecture/" rel="noopener noreferrer"&gt;hexagonal architecture&lt;/a&gt; of &lt;a href="https://martinfowler.com/bliki/DomainDrivenDesign.html" rel="noopener noreferrer"&gt;Domain-Driven-Design&lt;/a&gt; and layered architecture. Get to know the DDD Hamburger Architecture for Go and maybe it'll become your favorite too!&lt;/p&gt;

&lt;h2&gt;
  
  
  The DDD Hamburger Overview 🍔
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0kz65ijk1wf1029sj1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0kz65ijk1wf1029sj1b.png" alt="DDD Hamburger Overview" width="298" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The DDD Hamburger is a real Hamburger with well defined layers from top to bottom:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The upper Bun half&lt;/strong&gt; 🍞&lt;br&gt;
The upper bun half is the top of the Hamburger and is the &lt;em&gt;presentation layer&lt;/em&gt;. The presentation layer contains your REST API and the web interface. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Salad&lt;/strong&gt; 🥗&lt;br&gt;
Below the bun is the salad which is the &lt;em&gt;application layer&lt;/em&gt;. The application layer contains the use case logic of your application. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Meat&lt;/strong&gt; 🥩&lt;br&gt;
Next is the meat of your Hamburger, the &lt;em&gt;domain layer&lt;/em&gt;. Just like the meat the domain layer is the most important part of your Hamburger. The domain layer contains you domain logic and all entities, aggregates and value objects of your domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lower Bun half&lt;/strong&gt; 🍞&lt;br&gt;
The lower bun half is the &lt;em&gt;infrastructure layer&lt;/em&gt;. The infrastructure layer contains concrete implementations of your repositories for a Postgres database. The infrastructure layer implements interfaces declared in the domain layer.&lt;/p&gt;

&lt;p&gt;Got the idea? Great, so let's look into the details.&lt;/p&gt;
&lt;h2&gt;
  
  
  Go Example of the DDD Hamburger
&lt;/h2&gt;

&lt;p&gt;Now we'll code a Go application using our DDD Hamburger. We'll use a simple time tracking example application with activities to show the practical Go implementation. New activities are added using a REST API and are then stored in a Postgres database. &lt;/p&gt;

&lt;p&gt;The DDD Hamburger Architecture applied to Go is shown below. We'll go through all layers of the Hamburger in detail soon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6bjg2demyj0rstuiren6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6bjg2demyj0rstuiren6.png" alt="Go Example of the DDD Hamburger" width="800" height="1059"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Presentation Layer as upper Bun 🍞
&lt;/h2&gt;

&lt;p&gt;The presentation layer contains the HTTP handlers for the REST API. The HTTP handlers like &lt;code&gt;HandleCreateActivity&lt;/code&gt; create simple handler functions. All handlers for activities hang off a single struct &lt;code&gt;ActivityRestHandlers&lt;/code&gt;, as the code below shows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ActivityRestHandlers&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;actitivityService&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ActitivityService&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;a&lt;/span&gt; &lt;span class="n"&gt;ActivityRestHandlers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;HandleCreateActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&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;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The actual logic to create a new activity is handled by a service &lt;br&gt;
&lt;code&gt;ActivityService&lt;/code&gt; of the underlying application layer.&lt;/p&gt;

&lt;p&gt;The HTTP handlers don't use the activity entity of the domain layer as JSON representation. They use their own model for JSON which contains the struct tags to serialize it to JSON properly, as you see below.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;activityModel&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;ID&lt;/span&gt;          &lt;span class="kt"&gt;string&lt;/span&gt;        &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
    &lt;span class="n"&gt;Start&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt;        &lt;span class="s"&gt;`json:"start"`&lt;/span&gt;
    &lt;span class="n"&gt;End&lt;/span&gt;         &lt;span class="kt"&gt;string&lt;/span&gt;        &lt;span class="s"&gt;`json:"end"`&lt;/span&gt;
    &lt;span class="n"&gt;Duration&lt;/span&gt;    &lt;span class="n"&gt;durationModel&lt;/span&gt; &lt;span class="s"&gt;`json:"duration"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That way our presentation layer only depends on the application layer and the domain layer, not more. We allow relaxed layers, which means it's ok to skip the application layer and use stuff from the domain layer directly.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Application Layer as Salad 🥗
&lt;/h2&gt;

&lt;p&gt;The application layer contains service which implement the use cases of our application. One use case is to create an activity. This use case is implemented in the method &lt;code&gt;CreateActivity&lt;/code&gt; that hangs of the application service struct &lt;code&gt;ActitivityService&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ActitivityService&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;repository&lt;/span&gt; &lt;span class="n"&gt;ActivityRepository&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;a&lt;/span&gt; &lt;span class="n"&gt;ActitivityService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;CreateActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;savedActivity&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;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InsertActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// ... do more&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;savedActivity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The application services uses the repository interface &lt;code&gt;ActivityRepository&lt;/code&gt; for the use case. Yet it only knows the interface of the repository which is declared in the domain layer. The actual implementation of that interface is not of concern to the application layer.&lt;/p&gt;

&lt;p&gt;The application services also handle the transaction boundaries, since one use case shall be handled in one single atomic transaction. E.g. the use case of creating an new project with an initial activity for it has to go through in one transaction although it'll use one repository for activities and one for projects.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Domain Layer as Meat 🥩
&lt;/h2&gt;

&lt;p&gt;The most important part is the domain layer which is the meat of our DDD hamburger. The domain layer contains the domain entity &lt;code&gt;Activity&lt;/code&gt;, the logic of the domain like calculating the activity's duration and the interface of the activity repository.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Activity Entity&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Activity&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;ID&lt;/span&gt;             &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;
    &lt;span class="n"&gt;Start&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;Time&lt;/span&gt;
    &lt;span class="n"&gt;End&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;Time&lt;/span&gt;
    &lt;span class="n"&gt;Description&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;ProjectID&lt;/span&gt;      &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// -- Domain Logic&lt;/span&gt;
&lt;span class="c"&gt;// DurationDecimal is the activity duration as decimal (e.g. 0.75)&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;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;DurationDecimal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;float64&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;a&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Minutes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;60.0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// ActivityRepository&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ActivityRepository&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;InsertActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// ... lot's more&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The domain layer is the only layer that's not allowed to depend on other layers. It should also be implemented using mostly the Go standard library. That's why we neither use struct tags for json nor any database access code.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Infrastructure Layer as lower Bun 🍞
&lt;/h2&gt;

&lt;p&gt;The infrastructure layer contains the concrete implementation of the repository domain interface &lt;code&gt;ActivityRepository&lt;/code&gt; in the struct &lt;code&gt;DbActivityRepository&lt;/code&gt;. This repository implementation uses the Postgres driver &lt;a href="https://github.com/jackc/pgx" rel="noopener noreferrer"&gt;pgx&lt;/a&gt; and plain SQL to store the activity in the database. It uses the database transaction from the context, since the transaction was initiated by the application service.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// DbActivityRepository is a repository for a SQL database&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;DbActivityRepository&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;connPool&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgxpool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pool&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;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DbActivityRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;InsertActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Activity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContextKeyTx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pgx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;`INSERT INTO activities 
           (activity_id, start_time, end_time, description, project_id) 
         VALUES 
           ($1, $2, $3, $4, $5)`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;End&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProjectID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The infrastructure layer depends on the domain layer and may use all entities, aggregates and repository interfaces from the domain layer. But from the domain layer only.&lt;/p&gt;
&lt;h2&gt;
  
  
  Assemble the Burger in the Main Function
&lt;/h2&gt;

&lt;p&gt;No we have meat, salad and bun lying before us as single pieces. It's time to make a proper Hamburger out of these pieces. We assemble our Hamburger in the main function, as you see below.&lt;/p&gt;

&lt;p&gt;To wire the dependencies correctly together we work from bottom to top:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First we create a new instance of of the db activity repository &lt;code&gt;DbActivityRepository&lt;/code&gt; and pass in the database connection pool. &lt;/li&gt;
&lt;li&gt;Next we create the application service &lt;code&gt;ActivityService&lt;/code&gt; and pass in the repository.&lt;/li&gt;
&lt;li&gt;Now we create the &lt;code&gt;ActivityRestHandlers&lt;/code&gt; and pass in the application services. We now register the HTTP handler functions with the HTTP router.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code to assemble our DDD Hamburger architecture is 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="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="c"&gt;// ...&lt;/span&gt;

    &lt;span class="c"&gt;// Infrastructure Layer with concrete repository&lt;/span&gt;
    &lt;span class="n"&gt;repository&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDbActivityRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connectionPool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Application Layer with service&lt;/span&gt;
    &lt;span class="n"&gt;appService&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewActivityService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Presentation Layer with handlers&lt;/span&gt;
    &lt;span class="n"&gt;restHandlers&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tracking&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewActivityRestHandlers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/activity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;restHandlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleCreateActivity&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 code to assemble our Hamburger is plain, simple and very easy to understand. I like that, and it's all I usually need.&lt;/p&gt;
&lt;h2&gt;
  
  
  Package Structure for the DDD Hamburger
&lt;/h2&gt;

&lt;p&gt;One question remains: Which structure of our Go packages is best suited for the DDD Hamburger? &lt;/p&gt;

&lt;p&gt;I usually start out with a single package for all layers. So a single package &lt;code&gt;tracking&lt;/code&gt; with files &lt;code&gt;activity_rest.go&lt;/code&gt; for the rest handlers, &lt;code&gt;activity_service.go&lt;/code&gt; for application services, the domain layer in &lt;code&gt;activity_domain.go&lt;/code&gt; and the database repository in &lt;code&gt;activity_repository_db.go&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A next step is to separate out all layers as separate packages, except the domain layer. So we'd have a root package &lt;code&gt;tracking&lt;/code&gt;. The root package contains the domain layer. The root package has sub package for each layer like &lt;code&gt;application&lt;/code&gt;, &lt;code&gt;infrastructure&lt;/code&gt;, &lt;code&gt;presentation&lt;/code&gt;. Why the domain layer in the root package? That way we can use the domain layer with it's proper name. So if we'd use the domain entity &lt;code&gt;Activity&lt;/code&gt; somewhere, the code would read &lt;code&gt;tracking.Activity&lt;/code&gt; which is very nice to read.&lt;/p&gt;

&lt;p&gt;Whichever package structure is best depends on your project. I'd suggest you start small and easy and adjust it as your project grows over time.&lt;/p&gt;
&lt;h2&gt;
  
  
  Wrap Up of the DDD Hamburger 🍔
&lt;/h2&gt;

&lt;p&gt;The DDD Hamburger is a layered architecture based fully on Domain Driven Design. It's very easy to understand and follow. That's why the DDD Hamburger is my favorite architectural style. In general and especially in Go.&lt;/p&gt;

&lt;p&gt;Using the DDD Hamburger for your Go application is pretty straightforward, as you've seen. You can start out small yet you're able to grow as needed.&lt;/p&gt;

&lt;p&gt;See an application of the DDD Hamburger below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Baralga" rel="noopener noreferrer"&gt;
        Baralga
      &lt;/a&gt; / &lt;a href="https://github.com/Baralga/baralga-app" rel="noopener noreferrer"&gt;
        baralga-app
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Simple and lightweight time tracking for individuals and teams, for the cloud in the cloud.
    &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;Baralga&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Multi user time tracking application with web frontend and API.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;User Guide&lt;/h2&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Keyboard Shortcuts&lt;/h3&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Track Activities&lt;/h4&gt;

&lt;/div&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
Alt + Shift + n&lt;br&gt;
&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Add Activity&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
Alt + Shift + p&lt;br&gt;
&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Manage Projects&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h4 class="heading-element"&gt;Report Activities&lt;/h4&gt;

&lt;/div&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
Shift + Arrow Left&lt;br&gt;
&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Show previous Timespan&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
Shift + Arrow Down&lt;br&gt;
&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Show current Timespan&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;
&lt;br&gt;
Shift + Arrow Right&lt;br&gt;
&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Show next Timespan&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Administration&lt;/h2&gt;

&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Accessing the Web User Interface&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;The web user interface is available at &lt;code&gt;http://localhost:8080/&lt;/code&gt;. You can log in as administrator with &lt;code&gt;admin/adm1n&lt;/code&gt; or as user with &lt;code&gt;user1/us3r&lt;/code&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Configuration&lt;/h3&gt;

&lt;/div&gt;

&lt;p&gt;The backend is configured using the following environment variables:&lt;/p&gt;

&lt;p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;br&gt;
&lt;thead&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;th&gt;Environment Variable&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Default Value&lt;/th&gt;
&lt;br&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/thead&gt;
&lt;br&gt;
&lt;tbody&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;BARALGA_DB&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;postgres://postgres:postgres@localhost:5432/baralga&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;PostgreSQL Connection string for database&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;BARALGA_DBMAXCONNS&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Maximum number of database connections in pool.&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;PORT&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;8080&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;http server port&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;BARALGA_WEBROOT&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;&lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Web server root&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;BARALGA_JWTSECRET&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;secret&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Random secret for JWT generation&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;BARALGA_CSRFSECRET&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;CSRFsecret&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;Random secret for CSRF protection&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;BARALGA_ENV&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;dev&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;td&gt;use &lt;code&gt;production&lt;/code&gt; for production mode&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;tr&gt;
&lt;br&gt;
&lt;td&gt;&lt;code&gt;BARALGA_SMTPSERVERNAME&lt;/code&gt;&lt;/td&gt;
&lt;br&gt;
&lt;/tr&gt;
&lt;br&gt;
&lt;/tbody&gt;
&lt;br&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/p&gt;
&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Baralga/baralga-app" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;The DDD Hamburger Architecture was coined by &lt;a href="https://www.wps.de/wps/team/henning-schwentner" rel="noopener noreferrer"&gt;Henning Schwentner&lt;/a&gt;, so thanks for that. Another great influence for structuring the HTTP handlers came from &lt;a href="https://pace.dev/blog/2018/05/09/how-I-write-http-services-after-eight-years.html" rel="noopener noreferrer"&gt;Mat Ryer&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ddd</category>
      <category>go</category>
      <category>architecture</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Simplest WebServer for Angular in 6 Lines</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Mon, 17 Jul 2023 17:43:06 +0000</pubDate>
      <link>https://dev.to/remast/simplest-webserver-for-angular-in-6-lines-56l8</link>
      <guid>https://dev.to/remast/simplest-webserver-for-angular-in-6-lines-56l8</guid>
      <description>&lt;p&gt;How do you serve your Angular app? Learn to build a web server for your Angular app in 6 lines of code. Throw in 8 more lines and you have a multi stage Docker build for your web server along with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Angular Web Server in 6 Lines
&lt;/h2&gt;

&lt;p&gt;6 lines of code, that's all it takes for a simple Angular WebServer powered by &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddy&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:4200 {
        root * /usr/share/caddy
        encode gzip
        try_files {path} /index.html
        file_server
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Multi Stage Docker Build in 8 Lines
&lt;/h2&gt;

&lt;p&gt;Now let's throw in another 8 lines of code to get a multi stage Docker build for our Angular frontend. &lt;/p&gt;

&lt;p&gt;As a result you'll get a &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddy&lt;/a&gt; powered container of your Angular app.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Frontend Builder&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; . /app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm run build

&lt;span class="c"&gt;# 2. Frontend Container&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; caddy:2.6.4-alpine&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 4200&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Caddyfile /etc/caddy/Caddyfile&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /app/dist/frontend/* /usr/share/caddy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Check it out live and working in our Github repo below (folder frontend). Have fun and enjoy!!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/crossnative" rel="noopener noreferrer"&gt;
        crossnative
      &lt;/a&gt; / &lt;a href="https://github.com/crossnative/cloudland-rps" rel="noopener noreferrer"&gt;
        cloudland-rps
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Cloud native Rock, Paper, Scissors Workshop @CloudLand
    &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;Hello Cloudland! - Workshop Rock, Paper, Scissors&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://crossnative.github.io/cloudland-rps/" rel="nofollow noopener noreferrer"&gt;See documentation...&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Contents&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/crossnative/cloudland-rps/frontend/README.md" rel="noopener noreferrer"&gt;Frontend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/crossnative/cloudland-rps/backend-go/README.md" rel="noopener noreferrer"&gt;Go Backend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/crossnative/cloudland-rps/backend-spring/README.md" rel="noopener noreferrer"&gt;Spring Backend&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;OpenAPI Backend Specifcation&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/crossnative/cloudland-rpsrps_api.yml" rel="noopener noreferrer"&gt;Look here...&lt;/a&gt;&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/crossnative/cloudland-rps" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>angular</category>
      <category>webserver</category>
      <category>beginners</category>
      <category>spa</category>
    </item>
    <item>
      <title>Go Integration Tests using Testcontainers</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Mon, 29 Aug 2022 07:45:04 +0000</pubDate>
      <link>https://dev.to/remast/go-integration-tests-using-testcontainers-9o5</link>
      <guid>https://dev.to/remast/go-integration-tests-using-testcontainers-9o5</guid>
      <description>&lt;p&gt;Your application uses a database like Postgres? So how do you test your persistence layer to ensure it's working properly with a real &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;Postgres&lt;/a&gt; database? Right, you need to test against a real &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;Postgres&lt;/a&gt;. Since that test requires external infrastructure it's an &lt;em&gt;integration test&lt;/em&gt;. You'll learn how easy it is to write integration tests for your &lt;a href="https://go.dev/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; application using &lt;a href="https://golang.testcontainers.org/" rel="noopener noreferrer"&gt;Testcontainers&lt;/a&gt; and &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration Test Setup
&lt;/h2&gt;

&lt;p&gt;Our application stores users in a &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;Postgres&lt;/a&gt; database. It uses the struct &lt;code&gt;UserRepository&lt;/code&gt; with a method &lt;code&gt;FindByUsername&lt;/code&gt; that uses plain SQL to find a user by username. We will write an integration test running against a real &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;Postgres&lt;/a&gt; in &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; for the method &lt;code&gt;FindByUsername&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The integration test for the &lt;code&gt;FindByUsername&lt;/code&gt; of our &lt;code&gt;UserRepository&lt;/code&gt; looks like:&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;TestUserRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Setup database&lt;/span&gt;
    &lt;span class="n"&gt;dbContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connPool&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;SetupTestDatabase&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;dbContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Terminate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="c"&gt;// Create user repository&lt;/span&gt;
    &lt;span class="n"&gt;repository&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewUserRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connPool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Run tests against db&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FindExistingUserByUsername"&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;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;adminUser&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;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FindByUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoErr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;adminUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"admin"&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;First the database is set up. Then a new &lt;code&gt;UserRepository&lt;/code&gt; is created for the test with a reference to the connection pool of the database &lt;code&gt;connPool&lt;/code&gt;. No we run the method to test &lt;code&gt;userRepository.FindByUsername(ctx, "admin")&lt;/code&gt; and verify the result. But wait, where did that database container come from? Right, we'll set that up using &lt;a href="https://golang.testcontainers.org/" rel="noopener noreferrer"&gt;Testcontainers&lt;/a&gt; and &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Database Setup using Testcontainers
&lt;/h2&gt;

&lt;p&gt;We set up the &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;PostgreSQL&lt;/a&gt; database in a &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; container using the &lt;a href="https://golang.testcontainers.org/" rel="noopener noreferrer"&gt;Testcontainers&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;As a first step we create a &lt;code&gt;testcontainers.ContainerRequest&lt;/code&gt; where we set the Docker image to &lt;code&gt;postgres:14&lt;/code&gt; with exposed port &lt;code&gt;5432/tcp&lt;/code&gt;. The database name as well as username and password are set using environment variables. And to make sure the test only starts when the database container is up and running we wait for it using the &lt;code&gt;WaitingFor&lt;/code&gt; option with &lt;code&gt;wait.ForListeningPort("5432/tcp")&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now as second step we start the requested container.&lt;/p&gt;

&lt;p&gt;Finally in step 3 we use host and port of the running database container in the connection string for the database with &lt;code&gt;fmt.Sprintf("postgres://postgres:postgres@%v:%v/testdb", host, port.Port())&lt;/code&gt;. Now we connect with &lt;code&gt;pgxpool.Connect(context.Background(), dbURI)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The whole method &lt;code&gt;SetupTestDatabase&lt;/code&gt; to set up the PostgreSQL container is (errors omitted):&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;SetupTestDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testcontainers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgxpool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// 1. Create PostgreSQL container request&lt;/span&gt;
    &lt;span class="n"&gt;containerReq&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;testcontainers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContainerRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="s"&gt;"postgres:latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ExposedPorts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"5432/tcp"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;WaitingFor&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForListeningPort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"5432/tcp"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Env&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"POSTGRES_DB"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="s"&gt;"testdb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"POSTGRES_PASSWORD"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"POSTGRES_USER"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="s"&gt;"postgres"&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="c"&gt;// 2. Start PostgreSQL container&lt;/span&gt;
    &lt;span class="n"&gt;dbContainer&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;testcontainers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenericContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;testcontainers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenericContainerRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ContainerRequest&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;containerReq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Started&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// 3.1 Get host and port of PostgreSQL container&lt;/span&gt;
    &lt;span class="n"&gt;host&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;dbContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;port&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;dbContainer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MappedPort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"5432"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// 3.2 Create db connection string and connect&lt;/span&gt;
    &lt;span class="n"&gt;dbURI&lt;/span&gt; &lt;span class="o"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"postgres://postgres:postgres@%v:%v/testdb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;connPool&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;pgxpool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;dbURI&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;dbContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connPool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notice that we make sure the PostgreSQL container is terminated after our integration tests with &lt;code&gt;defer dbContainer.Terminate(context.Background())&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding Database Migrations
&lt;/h2&gt;

&lt;p&gt;So far our test starts out with an empty database. That's not very useful since we need the database tables of our application. In our example we need the table &lt;code&gt;users&lt;/code&gt;. We will now set up our database using &lt;a href="https://github.com/golang-migrate/migrate" rel="noopener noreferrer"&gt;golang-migrate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We add the database migrations to the &lt;code&gt;SetupTestDatabase()&lt;/code&gt; method by adding the call &lt;code&gt;MigrateDb(dbURI)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;SetupTestDatabase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testcontainers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pgxpool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ... (see before)&lt;/span&gt;

    &lt;span class="c"&gt;// 3.2 Create db connection string and connect&lt;/span&gt;
    &lt;span class="n"&gt;dbURI&lt;/span&gt; &lt;span class="o"&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;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"postgres://postgres:postgres@%v:%v/testdb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;MigrateDb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbURI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;connPool&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;pgxpool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;dbURI&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;dbContainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connPool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The method &lt;code&gt;MigrateDb(dbURI)&lt;/code&gt; applies the database migrations to the database using &lt;a href="https://github.com/golang-migrate/migrate" rel="noopener noreferrer"&gt;golang-migrate&lt;/a&gt;. The migration scripts are read from the directory &lt;code&gt;migrations&lt;/code&gt; which is embedded into the binary of our application.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//go:embed migrations&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt; &lt;span class="n"&gt;embed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FS&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;MigrateDb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbURI&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;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;source&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;iofs&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;migrations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"migrations"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewWithSourceInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"iofs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dbURI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"postgres://"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pgx5://"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;defer&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;Close&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;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Up&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="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;migrate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrNoChange&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;We have a working setup for integration tests against a real &lt;a href="https://www.postgresql.org/" rel="noopener noreferrer"&gt;Postgres&lt;/a&gt; database running in &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; using &lt;a href="https://golang.testcontainers.org/" rel="noopener noreferrer"&gt;Testcontainers&lt;/a&gt;. We can use this setup for integration tests of our persistence layer. But that's not all it's good for.&lt;/p&gt;

&lt;p&gt;This setup is a great way for all kinds of integration tests that need infrastructure. E.g. a test that send emails to an mail server running in docker, as in &lt;a href="https://github.com/Baralga/baralga-app/blob/main/shared/mail_resource_smtp_test.go" rel="noopener noreferrer"&gt;mail_resource_smtp_test.go&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/remast" rel="noopener noreferrer"&gt;
        remast
      &lt;/a&gt; / &lt;a href="https://github.com/remast/go-for-testcontainers" rel="noopener noreferrer"&gt;
        go-for-testcontainers
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Demo for Testcontainers in Go
    &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;Go for Testcontainers&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Sample code for my post &lt;a href="https://medium.com/@remast/go-integration-tests-using-testcontainers-8877e4b1c811" rel="nofollow noopener noreferrer"&gt;Go for Testcontainers&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/remast/go-for-testcontainers" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>go</category>
      <category>beginners</category>
      <category>devops</category>
      <category>database</category>
    </item>
    <item>
      <title>Local Dev Setup with automatic HTTPS + WebSockets in 1 Line</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Sun, 07 Feb 2021 15:30:46 +0000</pubDate>
      <link>https://dev.to/remast/local-dev-setup-with-automatic-https-websockets-in-1-line-28le</link>
      <guid>https://dev.to/remast/local-dev-setup-with-automatic-https-websockets-in-1-line-28le</guid>
      <description>&lt;p&gt;Let's set up a local web server for development that supports automatic HTTPs and WebSockets in just 1 line of code. No problem thanks to the awesome &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddyserver&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Set up the local hostname
&lt;/h3&gt;

&lt;p&gt;For automatic HTTPs you need to set up a local hostname first. We will use &lt;code&gt;remast.local&lt;/code&gt;. To make your local development machine available at that hostname you need to add the hostname to your local hosts file.&lt;/p&gt;

&lt;p&gt;So locate the hosts file on your machine and add the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127.0.0.1   remast.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's where you find the hosts file in your operating system.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operating System&lt;/th&gt;
&lt;th&gt;Location of hosts file&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Windows 10&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C:\Windows\System32\drivers\etc\hosts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/etc/hosts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mac OS X&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/private/etc/hosts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now verify by testing to reach the hostname via ping with &lt;code&gt;ping remast.local&lt;/code&gt;. If that takes you to &lt;code&gt;127.0.0.1&lt;/code&gt; everything is fine and you can proceed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Caddyserver
&lt;/h3&gt;

&lt;p&gt;Now install &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddyserver&lt;/a&gt; on your machine. If you're on Windows and use the &lt;a href="https://chocolatey.org" rel="noopener noreferrer"&gt;Chocolatey package manager&lt;/a&gt; you can do that with &lt;code&gt;choco install caddy&lt;/code&gt;. For other plattforms check the &lt;a href="https://caddyserver.com/docs/install" rel="noopener noreferrer"&gt;Caddyserver install docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting the local dev server with HTTPs and WebSockets
&lt;/h2&gt;

&lt;p&gt;Now off we go with our local dev server with automatic HTTPs and WebSocket support. Here's the only one line you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;caddy reverse-proxy --from remast.local --to 127.0.0.1:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This one line will fire up your local &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddyserver&lt;/a&gt; which will automaticlally start HTTPs and proxy all requests including WebSockets. How cool is that?!&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the Caddyfile
&lt;/h3&gt;

&lt;p&gt;Of course you can always save your configuration in file called &lt;code&gt;Caddyfile&lt;/code&gt;, with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remast.local {
    reverse_proxy 127.0.0.1:8080
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What's next?
&lt;/h3&gt;

&lt;p&gt;Once you've made your first steps &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddyserver&lt;/a&gt; there's no way back. Caddy is really awesome for both development and production!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Turbo Streams powered by Go WebSockets</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Wed, 30 Dec 2020 21:04:31 +0000</pubDate>
      <link>https://dev.to/remast/turbo-streams-powered-by-go-websockets-1578</link>
      <guid>https://dev.to/remast/turbo-streams-powered-by-go-websockets-1578</guid>
      <description>&lt;p&gt;&lt;a href="https://turbo.hotwire.dev/" rel="noopener noreferrer"&gt;Turbo&lt;/a&gt; is a new way to build greate web frontends fully powered by html markup and without any JavaScript. That &lt;a href="https://turbo.hotwire.dev/" rel="noopener noreferrer"&gt;Turbo&lt;/a&gt; is what powers &lt;a href="https://basecamp.com/" rel="noopener noreferrer"&gt;Basecamps&lt;/a&gt; new mail service &lt;a href="https://hey.com/" rel="noopener noreferrer"&gt;HeyHey&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At the heart of &lt;a href="https://turbo.hotwire.dev/" rel="noopener noreferrer"&gt;Turbo&lt;/a&gt; are &lt;a href="https://turbo.hotwire.dev/reference/streams" rel="noopener noreferrer"&gt;Streams&lt;/a&gt; which provides realtime updates over HTTP or WebSocket.&lt;/p&gt;

&lt;p&gt;With Turbo Streams you just sent dom updates over the wire as plain html. Like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;turbo-stream&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"append"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"dom_id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
    Content to append to container designated with the dom_id.
  &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/turbo-stream&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then the html sent over in the &lt;code&gt;template&lt;/code&gt; element is appended to the dom element with id &lt;code&gt;dom_id&lt;/code&gt;. Just so simple. Of course you can also replace or remove html from the dom the same way by using the actions &lt;code&gt;repace&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For all you Gophers out there keen on using it, I've got you covered! Here's a simple example for using Turbos Streams in &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; &lt;br&gt;
 with the &lt;a href="https://github.com/gorilla/websocket" rel="noopener noreferrer"&gt;Gorilla WebSocket&lt;/a&gt; toolkit.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/remast" rel="noopener noreferrer"&gt;
        remast
      &lt;/a&gt; / &lt;a href="https://github.com/remast/go_websocket_turbo" rel="noopener noreferrer"&gt;
        go_websocket_turbo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Simple example for using Turbos Streams in Go with the Gorilla WebSocket toolkit.
    &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;Go Example for TurboStreams over WebSockets&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Simple example for using &lt;a href="https://turbo.hotwire.dev/" rel="nofollow noopener noreferrer"&gt;Turbo&lt;/a&gt;s &lt;a href="https://turbo.hotwire.dev/reference/streams" rel="nofollow noopener noreferrer"&gt;Stream&lt;/a&gt;s in Go with the &lt;a href="https://github.com/gorilla/websocket" rel="noopener noreferrer"&gt;Gorilla WebSocket&lt;/a&gt; toolkit.&lt;/p&gt;

&lt;p&gt;Run the sample using the following command:&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;$ go run *.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To use the chat example, open &lt;a href="http://localhost:8080/" rel="nofollow noopener noreferrer"&gt;http://localhost:8080/&lt;/a&gt; in your browser.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Frontend&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;The frontend connects to the Turbo Stream using plain JavaScript like:&lt;/p&gt;

&lt;div class="highlight highlight-text-html-basic notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt; &lt;span class="pl-c1"&gt;src&lt;/span&gt;="&lt;span class="pl-s"&gt;https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.4/dist/turbo.es2017-umd.min.js&lt;/span&gt;" &lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="pl-v"&gt;Turbo&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;connectStreamSource&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-v"&gt;WebSocket&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"ws://"&lt;/span&gt; &lt;span class="pl-c1"&gt;+&lt;/span&gt; &lt;span class="pl-smi"&gt;document&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;location&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;host&lt;/span&gt; &lt;span class="pl-c1"&gt;+&lt;/span&gt; &lt;span class="pl-s"&gt;"/ws"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="pl-ent"&gt;script&lt;/span&gt;&lt;span class="pl-kos"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;After that the frontend is connected to the Turbo Stream and get's all messages. Every chat message is appended to the dom element with id &lt;code&gt;board&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This &lt;em&gt;should&lt;/em&gt; work with html markup too but I have not gotten it working yet.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Server&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;The server receives the new chat message via web socket. Then it wraps the message as Turbo Stream…&lt;/p&gt;
&lt;/div&gt;


&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/remast/go_websocket_turbo" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>go</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>5 Great Go Resources</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Fri, 24 Jul 2020 13:57:32 +0000</pubDate>
      <link>https://dev.to/remast/5-great-go-resources-3njc</link>
      <guid>https://dev.to/remast/5-great-go-resources-3njc</guid>
      <description>&lt;p&gt;Here are 5 great resources for all you Gophers out there:&lt;/p&gt;

&lt;h1&gt;
  
  
  Awesome Go
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/avelino" rel="noopener noreferrer"&gt;
        avelino
      &lt;/a&gt; / &lt;a href="https://github.com/avelino/awesome-go" rel="noopener noreferrer"&gt;
        awesome-go
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A curated list of awesome Go frameworks, libraries and software
    &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;Awesome Go&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://awesome-go.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Favelino%2Fawesome-go%2Fraw%2Fmain%2Ftmpl%2Fassets%2Flogo.png" alt="awesome-go" title="awesome-go"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/avelino/awesome-go/actions/workflows/tests.yaml?query=branch%3Amain" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/avelino/awesome-go/actions/workflows/tests.yaml/badge.svg?branch=main" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://github.com/sindresorhus/awesome" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8693bde04030b1670d5097703441005eba34240c32d1df1eb82a5f0d6716518e/68747470733a2f2f63646e2e7261776769742e636f6d2f73696e647265736f726875732f617765736f6d652f643733303566333864323966656437386661383536353265336136336531353464643865383832392f6d656469612f62616467652e737667" alt="Awesome"&gt;&lt;/a&gt;
&lt;a href="https://gophers.slack.com/messages/awesome" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c05034a4b7528510149f91f488774302aad7e4a5a9769ec3be2700b14105d712/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6a6f696e2d75732532306f6e253230736c61636b2d677261792e7376673f6c6f6e6743616368653d74727565266c6f676f3d736c61636b26636f6c6f72423d726564" alt="Slack Widget"&gt;&lt;/a&gt;
&lt;a href="https://app.netlify.com/sites/awesome-go/deploys" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/bc4fb49bf3efa53dde29731ad9dea3ee49f6c0091f6b271413d7d4d7d649da58/68747470733a2f2f6170692e6e65746c6966792e636f6d2f6170692f76312f6261646765732f38336136646362652d306461362d343333652d623538362d6636383130393238366264352f6465706c6f792d737461747573" alt="Netlify Status"&gt;&lt;/a&gt;
&lt;a href="https://www.trackawesomelist.com/avelino/awesome-go/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/880c818cab09e423f192563dcd39870d0641ffebc12199a46dd42ece966cef30/68747470733a2f2f7777772e747261636b617765736f6d656c6973742e636f6d2f62616467652e737667" alt="Track Awesome List"&gt;&lt;/a&gt;
&lt;a href="https://img.shields.io/github/last-commit/avelino/awesome-go" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/629ddfa705a816149cbf00cc65ad6d7da93b20fac0981028f4e4d5c68d194c0b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f6176656c696e6f2f617765736f6d652d676f" alt="Last Commit"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We use the &lt;em&gt;&lt;a href="https://github.com/gobridge/about-us/blob/master/README.md" rel="noopener noreferrer"&gt;Golang Bridge&lt;/a&gt;&lt;/em&gt; community Slack for instant communication, follow the &lt;a href="https://invite.slack.golangbridge.org/" rel="nofollow noopener noreferrer"&gt;form here to join&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.producthunt.com/posts/awesome-go?utm_source=badge-featured&amp;amp;utm_medium=badge&amp;amp;utm_souce=badge-awesome-go" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/46c2eb9ef5532f6e5fd8dcacd9cbc2696af861ebb65077d86f1be26a6172fe3e/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f66656174757265642e7376673f706f73745f69643d323931353335267468656d653d6c69676874" alt="awesome-go - Curated list awesome Go frameworks, libraries and software | Product Hunt" width="250" height="54"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sponsorships:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Special thanks to&lt;/em&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td colspan="2"&gt;
&lt;a href="https://bit.ly/awesome-go-workos" rel="nofollow noopener noreferrer"&gt;
&lt;img src="https://camo.githubusercontent.com/e47926d4a9bbbf13557785b6718d97d1c81260b555d39212524eb1f4c3a512c1/68747470733a2f2f6176656c696e6f2e72756e2f73706f6e736f72732f776f726b6f732d6c6f676f2d77686974652d62672e737667" width="200" alt="WorkOS"&gt;&lt;br&gt;
&lt;b&gt;Your app, enterprise-ready.&lt;/b&gt;&lt;br&gt;
Start selling to enterprise customers with just a few lines of code.&lt;br&gt;
&lt;sup&gt;Add Single Sign-On (and more) in minutes instead of months.&lt;/sup&gt;
&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="2"&gt;
&lt;a href="https://bit.ly/awesome-go-digitalocean" rel="nofollow noopener noreferrer"&gt;
&lt;img src="https://camo.githubusercontent.com/13c20e2c2049176843b8695e67ae61c74dd905b0b373ad1cd717be6c03273d84/68747470733a2f2f6176656c696e6f2e72756e2f73706f6e736f72732f646f5f6c6f676f5f686f72697a6f6e74616c5f626c75652d3231302e706e67" width="200" alt="Digital Ocean"&gt;
&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Awesome Go has no monthly fee&lt;/strong&gt;&lt;em&gt;, but we have employees who &lt;strong&gt;work hard&lt;/strong&gt; to keep it running. With money raised, we can repay the effort of each person involved! You can see how we calculate our billing and distribution as it is open to the entire community. Want to be a supporter of the project click &lt;a href="https://github.com/avelino/awesome-gomailto:avelinorun+oss@gmail.com?subject=awesome-go%3A%20project%20support" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A curated list of awesome Go frameworks, libraries, and software. Inspired by &lt;a href="https://github.com/vinta/awesome-python" rel="noopener noreferrer"&gt;awesome-python&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Contributing:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Please take a quick gander at the &lt;a href="https://github.com/avelino/awesome-go/blob/main/CONTRIBUTING.md" rel="noopener noreferrer"&gt;contribution guidelines&lt;/a&gt; first. Thanks to all &lt;a href="https://github.com/avelino/awesome-go/graphs/contributors" rel="noopener noreferrer"&gt;contributors&lt;/a&gt;; you rock!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you see a package or project here that is no&lt;/em&gt;…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/avelino/awesome-go" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Go Training Courses and Material by Ardanlabs
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ardanlabs" rel="noopener noreferrer"&gt;
        ardanlabs
      &lt;/a&gt; / &lt;a href="https://github.com/ardanlabs/gotraining" rel="noopener noreferrer"&gt;
        gotraining
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Go Training Class Material : 
    &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;h2 class="heading-element"&gt;Go Training&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://circleci.com/gh/ardanlabs/gotraining" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2eaab367e530363489713611b7571ac39b6f7f180c3913e7b906e11c893329b6/68747470733a2f2f636972636c6563692e636f6d2f67682f617264616e6c6162732f676f747261696e696e672e7376673f7374796c653d737667" alt="CircleCI"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/ardanlabs/gotrainingtopics/README.md" rel="noopener noreferrer"&gt;Review our different courses and material&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Copyright 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, Ardan Labs&lt;br&gt;
&lt;a href="https://github.com/ardanlabs/gotrainingmailto:hello@ardanlabs.com" rel="noopener noreferrer"&gt;hello@ardanlabs.com&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Learn More&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Reach out about corporate training events, open enrollment live training sessions, and on-demand learning options.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ardan Labs (&lt;a href="http://www.ardanlabs.com" rel="nofollow noopener noreferrer"&gt;www.ardanlabs.com&lt;/a&gt;)&lt;br&gt;
&lt;a href="https://github.com/ardanlabs/gotrainingmailto:hello@ardanlabs.com" rel="noopener noreferrer"&gt;hello@ardanlabs.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To attend any of our high-performance tranings check out this link:&lt;br&gt;
&lt;a href="https://www.ardanlabs.com/training" rel="nofollow noopener noreferrer"&gt;https://www.ardanlabs.com/training&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Index&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining#purchase-video--book" rel="noopener noreferrer"&gt;Purchase Video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining#our-experience" rel="noopener noreferrer"&gt;Experience&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining#our-teachers" rel="noopener noreferrer"&gt;Teachers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining#more-about-go" rel="noopener noreferrer"&gt;More About Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining#minimal-qualified-student" rel="noopener noreferrer"&gt;Minimal Qualified Student&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining#important-reading" rel="noopener noreferrer"&gt;Important Reading&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining#before-you-come-to-class" rel="noopener noreferrer"&gt;Before You Come To Class&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining#twitter" rel="noopener noreferrer"&gt;Twitter Reactions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ardanlabs/gotraining#testimonials" rel="noopener noreferrer"&gt;Testimonials&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Purchase Video / Book&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;The entire training class has been recorded to be made available to those who can't have the class taught at their company or who can't attend a conference. This is the entire class material.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://education.ardanlabs.com" rel="nofollow noopener noreferrer"&gt;education.ardanlabs.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There is a book for all of the material in the class.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://education.ardanlabs.com/courses/ultimate-go-notebook" rel="nofollow noopener noreferrer"&gt;Ultimate Go Notebook&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Our Experience&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;We have taught Go to thousands of developers all around the world since 2014. There is no other…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ardanlabs/gotraining" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Idiomatic Go Resources
&lt;/h1&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@dgryski/idiomatic-go-resources-966535376dba" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fv2%2Fresize%3Afill%3A64%3A64%2F0%2AL9crslCOgtVnuOSf.png" alt="Damian Gryski"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@dgryski/idiomatic-go-resources-966535376dba" class="ltag__link__link" rel="noopener noreferrer"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Idiomatic Go Resources. Every time the discussion comes up… | by Damian Gryski | Medium&lt;/h2&gt;
      &lt;h3&gt;Damian Gryski ・ &lt;time&gt;Jul 31, 2020&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fmedium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Security Related Resources for Go
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/guardrailsio" rel="noopener noreferrer"&gt;
        guardrailsio
      &lt;/a&gt; / &lt;a href="https://github.com/guardrailsio/awesome-golang-security" rel="noopener noreferrer"&gt;
        awesome-golang-security
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Awesome Golang Security resources 🕶🔐
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;br&gt;
&lt;div&gt;
&lt;p&gt;A curated list of awesome golang Security related resources.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://awesome.re" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3418ba3754faddfb88c5cbdc94c31ad670fc693c8caa59bc2806c9836acc04e4/68747470733a2f2f617765736f6d652e72652f62616467652e737667" alt="Awesome"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;List inspired by the &lt;a href="https://github.com/sindresorhus/awesome" rel="noopener noreferrer"&gt;awesome&lt;/a&gt; list thing.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Supported by: &lt;a href="https://www.guardrails.io" rel="nofollow noopener noreferrer"&gt;GuardRails.io&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Contents&lt;/h1&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/guardrailsio/awesome-golang-security#tools" rel="noopener noreferrer"&gt;Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/guardrailsio/awesome-golang-security#educational" rel="noopener noreferrer"&gt;Educational&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/guardrailsio/awesome-golang-security#other" rel="noopener noreferrer"&gt;Other&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/guardrailsio/awesome-golang-security#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Tools&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Web Framework Hardening&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/justinas/nosurf" rel="noopener noreferrer"&gt;nosurf&lt;/a&gt; - CSRF protection middleware for Go.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gorilla/csrf" rel="noopener noreferrer"&gt;gorilla/csrf&lt;/a&gt; - Provides Cross-Site Request Forgery (CSRF) prevention middleware for Go web applications &amp;amp; services.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gorilla/securecookie" rel="noopener noreferrer"&gt;gorilla/securecookie&lt;/a&gt; - Encodes and decodes authenticated and optionally encrypted cookie values for Go web applications.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/unrolled/secure" rel="noopener noreferrer"&gt;secure&lt;/a&gt; -  Secure is an HTTP middleware for Go that facilitates most of your security needs for web applications.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jordan-wright/unindexed" rel="noopener noreferrer"&gt;unindexed&lt;/a&gt; - A drop-in replacement for &lt;code&gt;http.Dir&lt;/code&gt; which disables directory indexing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/gosecguy/beego-security-headers" rel="noopener noreferrer"&gt;beego-security-headers&lt;/a&gt; - beego framework filter for easy security headers management.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Libraries&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/o1egl/paseto" rel="noopener noreferrer"&gt;paseto&lt;/a&gt; - Platform-Agnostic Security Tokens implementation in GO (Golang).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/StalkR/hsts" rel="noopener noreferrer"&gt;hsts&lt;/a&gt; - Go HTTP Strict Transport Security library.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dgrijalva/jwt-go" rel="noopener noreferrer"&gt;jwt-go&lt;/a&gt; - Golang implementation of JSON Web Tokens (JWT).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tomnomnom/httprobe" rel="noopener noreferrer"&gt;httprobe&lt;/a&gt; - Take a list of domains and probe for working HTTP and HTTPS servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Static Code Analysis&lt;/h2&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/guardrailsio/awesome-golang-security" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Style Guides for Go
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/dgryski" rel="noopener noreferrer"&gt;
        dgryski
      &lt;/a&gt; / &lt;a href="https://github.com/dgryski/awesome-go-style" rel="noopener noreferrer"&gt;
        awesome-go-style
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A collection of Go style guides
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;This is a collection of style guides for Go.&lt;/p&gt;
&lt;p&gt;Be sure to read about &lt;a href="https://medium.com/@dgryski/writing-engineering-guidelines-24fdda53a3f0" rel="nofollow noopener noreferrer"&gt;writing engineering
guidelines&lt;/a&gt;
before trying to adopt one of these wholesale.&lt;/p&gt;
&lt;p&gt;(For more commentary on these, see my blog post &lt;a href="https://medium.com/@dgryski/idiomatic-go-resources-966535376dba" rel="nofollow noopener noreferrer"&gt;Idiomatic Go Resources&lt;/a&gt;)&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;The Classics&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://google.github.io/styleguide/go/index" rel="nofollow noopener noreferrer"&gt;Go Style (Google Style Guides)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://golang.org/doc/effective_go.html" rel="nofollow noopener noreferrer"&gt;Effective Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/go/wiki/CodeReviewComments" rel="noopener noreferrer"&gt;CodeReviewComments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://go-proverbs.github.io" rel="nofollow noopener noreferrer"&gt;Go Proverbs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Googler Talks&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://talks.golang.org/2014/names.slide#1" rel="nofollow noopener noreferrer"&gt;What’s in a name?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.golang.org/package-names" rel="nofollow noopener noreferrer"&gt;Package Names&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://talks.golang.org/2014/readability.slide#1" rel="nofollow noopener noreferrer"&gt;When in Go, do as Gophers do&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://talks.golang.org/2013/bestpractices.slide#1" rel="nofollow noopener noreferrer"&gt;Twelve Go Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rakyll.org/style-packages/" rel="nofollow noopener noreferrer"&gt;Style guidelines for Go packages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dmitri.shuralyov.com/idiomatic-go" rel="nofollow noopener noreferrer"&gt;Idiomatic Go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Go Wiki Pages&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/go/wiki/TargetSpecific" rel="noopener noreferrer"&gt;Target-specific code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/go/wiki/AssemblyPolicy" rel="noopener noreferrer"&gt;Assembly Policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/go/wiki/CommitMessage" rel="noopener noreferrer"&gt;Commit Messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/go/wiki/TestComments" rel="noopener noreferrer"&gt;TestComments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Non-Googlers&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://peter.bourgon.org/go-best-practices-2016/" rel="nofollow noopener noreferrer"&gt;Go Best Practices 2016&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peter.bourgon.org/go-for-industrial-programming/" rel="nofollow noopener noreferrer"&gt;Go for Industrial Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dave.cheney.net/practical-go/presentations/qcon-china.html" rel="nofollow noopener noreferrer"&gt;Practical Go: Real world advice for writing maintainable Go programs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dave.cheney.net/2020/02/23/the-zen-of-go" rel="nofollow noopener noreferrer"&gt;The Zen of Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://godoc.org/github.com/natefinch/godocgo" rel="nofollow noopener noreferrer"&gt;godocgo: Effective Go documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Further Reading&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@dgryski/the-ideas-that-shaped-go-21850a74295f" rel="nofollow noopener noreferrer"&gt;The Ideas That Shaped Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/1702.01715" rel="nofollow noopener noreferrer"&gt;Software Engineering at Google&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Corporate/Project-specific Style Guildes&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/bahlo/go-styleguide" rel="noopener noreferrer"&gt;bahlo/go-styleguide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cockroachdb/cockroach/blob/master/docs/style.md" rel="noopener noreferrer"&gt;CockroachDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.edgexfoundry.org/display/FA/Contributor%27s+Guide+-+Go+Lang" rel="nofollow noopener noreferrer"&gt;Edge X Foundry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.gitlab.com/ee/development/go_guide/" rel="nofollow noopener noreferrer"&gt;GitLab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/hyperledger/fabric/blob/release-1.4/docs/source/style-guides/go-style.rst" rel="noopener noreferrer"&gt;Hyperledger&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/boramalper/magnetico/wiki/magnetico-Design-Specification" rel="noopener noreferrer"&gt;Magnetico&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://about.sourcegraph.com/handbook/engineering/go_style_guide" rel="nofollow noopener noreferrer"&gt;Sourcegraph&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thanos.io/tip/contributing/coding-style-guide.md/" rel="nofollow noopener noreferrer"&gt;Thanos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/uber-go/guide/blob/master/style.md" rel="noopener noreferrer"&gt;Uber&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;General tips for Code Reviews:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vitess.io/docs/contributing/code-reviews/" rel="nofollow noopener noreferrer"&gt;Vitess.io Code Reviews&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://google.github.io/eng-practices/" rel="nofollow noopener noreferrer"&gt;Google Engineering Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/dgryski/awesome-go-style" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>go</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Using SonarCloud with Github Actions and Maven</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Sat, 07 Mar 2020 21:40:33 +0000</pubDate>
      <link>https://dev.to/remast/using-sonarcloud-with-github-actions-and-maven-31kg</link>
      <guid>https://dev.to/remast/using-sonarcloud-with-github-actions-and-maven-31kg</guid>
      <description>&lt;p&gt;In this post you will will learn how to analyse your Java &lt;a href="https://maven.apache.org/" rel="noopener noreferrer"&gt;Maven&lt;/a&gt; project with &lt;a href="https://sonarcloud.io/" rel="noopener noreferrer"&gt;SonarCloud&lt;/a&gt; using &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Starting point is a simple Java project with a Maven build. First we'll use &lt;a href="https://sonarcloud.io/" rel="noopener noreferrer"&gt;SonarCloud&lt;/a&gt; to analyze our source code from our local dev environment. Then we'll use Github Actions to run the Maven build. So finally we have a fully functional ci pipeline which builds and analyzes our code using Github Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up SonarCloud
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Create a Project
&lt;/h3&gt;

&lt;p&gt;In order to use &lt;a href="https://sonarcloud.io/" rel="noopener noreferrer"&gt;SonarCloud&lt;/a&gt; you need to create an account and set up a project. So first create an account and log in. Now you can create a new project &lt;a href="https://sonarcloud.io/projects/create" rel="noopener noreferrer"&gt;here&lt;/a&gt; or using the '+' button. A project in SonarCloud must belong to an organization. SonarCloud automatically imports your Github organizations. So you can use any of your Github organizations or use the default organization by your Github user name. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2020-03_SonarCloud_with_GithubAction_and_Maven%2FSonarCloud_CreateProject.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2020-03_SonarCloud_with_GithubAction_and_Maven%2FSonarCloud_CreateProject.png" alt="SonarCloud Create Project" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you've created your project, your project has an organization key and a project key. You'll need both to run an SonarCloud analysis. You can always look up organization key and project key from the dashboard&lt;br&gt;
of your project like shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2020-03_SonarCloud_with_GithubAction_and_Maven%2FSonarCloud_ProjectKey.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2020-03_SonarCloud_with_GithubAction_and_Maven%2FSonarCloud_ProjectKey.png" alt="SonarCloud Project Key" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Generate a SonarCloud Token
&lt;/h3&gt;

&lt;p&gt;Now we'll set up a secure token as authentication for SonarCloud. Generate a new token from the tab 'security' in your account settings (which is &lt;a href="https://sonarcloud.io/account/security/" rel="noopener noreferrer"&gt;here&lt;/a&gt;). Make sure to store the token since you'll only see it right after you've greated it. Now you're all set up to run a first analysis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2020-03_SonarCloud_with_GithubAction_and_Maven%2FSonarCloud_GenerateToken.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2020-03_SonarCloud_with_GithubAction_and_Maven%2FSonarCloud_GenerateToken.png" alt="SonarCloud Generate Token" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Run SonarCloud analysis locally using Maven
&lt;/h2&gt;

&lt;p&gt;You can run the SonarCloud analysis using maven. The organization key, project key and the generated token must be passed to the &lt;a href="https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-maven/" rel="noopener noreferrer"&gt;Sonar Maven Plugin&lt;/a&gt; as well as the url for SonarCloud. Replace &lt;code&gt;&amp;lt;GENERATED_TOKEN&amp;gt;&lt;/code&gt; with the SonarCloud token you generated in the previous step. So the command is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn sonar:sonar &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-Dsonar&lt;/span&gt;.projectKey&lt;span class="o"&gt;=&lt;/span&gt;baralga &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-Dsonar&lt;/span&gt;.organization&lt;span class="o"&gt;=&lt;/span&gt;baralga &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-Dsonar&lt;/span&gt;.host.url&lt;span class="o"&gt;=&lt;/span&gt;https://sonarcloud.io &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-Dsonar&lt;/span&gt;.login&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;GENERATED_TOKEN&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After you ran the analysis the results will shortly be online in the SonarCloud dashboard at &lt;code&gt;https://sonarcloud.io/dashboard?id=&amp;lt;projectKey&amp;gt;&lt;/code&gt;. The dashboard for our sample project &lt;code&gt;baralga&lt;/code&gt; is available at &lt;a href="https://sonarcloud.io/dashboard?id=baralga" rel="noopener noreferrer"&gt;https://sonarcloud.io/dashboard?id=baralga&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Run SonarCloud analysis using Github Actions
&lt;/h2&gt;

&lt;p&gt;Now we will use Github Actions to run the SonarCloud analysis from our ci pipeline. We'll use Maven for that like we did before. We set up Github Action that runs the SonarClound analysis using Maven. Like before we pass organization key and project key as parameters. Additionally we need to provide the SonarCloud token and the &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token" rel="noopener noreferrer"&gt;Github Token&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The token for SonarCloud is stored as a encrypted secret as described &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets" rel="noopener noreferrer"&gt;here&lt;/a&gt;. We can access it in our Github Action with &lt;code&gt;${{ secrets.SONAR_TOKEN }}&lt;/code&gt;. The &lt;a href="https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token" rel="noopener noreferrer"&gt;Github Token&lt;/a&gt; is already provided by Github Actions itself and we can access it with &lt;code&gt;${{ secrets.GITHUB_TOKEN }}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And here's the complete Github Action workflow. Save it in the file &lt;code&gt;.github\workflows\sonar.yml&lt;/code&gt; and off you go.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SonarCloud&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-16.04&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up JDK&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;11'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Analyze with SonarCloud&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./mvnw -B verify sonar:sonar -Dsonar.projectKey=baralga -Dsonar.organization=baralga -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=$SONAR_TOKEN&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
        &lt;span class="na"&gt;SONAR_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SONAR_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now every build of your Github Actions pipeline analyzes the code using SonarCloud. That looks like below or see it live in action in the &lt;a href="https://github.com/Baralga/baralga/actions" rel="noopener noreferrer"&gt;Baralga Actions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2020-03_SonarCloud_with_GithubAction_and_Maven%2FSonarCloud_GithubActionsBuild.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2020-03_SonarCloud_with_GithubAction_and_Maven%2FSonarCloud_GithubActionsBuild.png" alt="Baralga SonarCloud Build" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Topping it off with Code Coverage
&lt;/h2&gt;

&lt;p&gt;As last step we add the code coverage of our unit tests to SonarCloud. &lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: Calculate Test Coverage with Jacoco
&lt;/h3&gt;

&lt;p&gt;We use &lt;a href="https://www.eclemma.org/jacoco/" rel="noopener noreferrer"&gt;Jacoco&lt;/a&gt; to calculate the code coverage of our tests. For that we add the &lt;a href="https://www.eclemma.org/jacoco/trunk/doc/maven.html" rel="noopener noreferrer"&gt;jacoco-maven-plugin&lt;/a&gt; to our &lt;code&gt;pom.xml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
  ...
  &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jacoco&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jacoco-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.8.5&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;prepare-agent&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;prepare-agent&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;report&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;prepare-package&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;report&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We tell SonarCloud where to find the calculated code coverage using the parameter &lt;code&gt;-Dsonar.coverage.jacoco.xmlReportPaths=${project.build.directory}/site/jacoco/jacoco.xml&lt;/code&gt; for our Maven build. After the next build the code coverage will show up in SonarCloud.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Step by step we introduced SonarCloud to analyze our code within our ci pipeline using Github Actions. Whenever the ci pipeline runs, the code is analyzed using SonarCloud and the results and metrics are available&lt;br&gt;
in the SonarCloud dashboard. You can find a working example at &lt;a href="https://github.com/Baralga/baralga" rel="noopener noreferrer"&gt;baralga&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Baralga" rel="noopener noreferrer"&gt;
        Baralga
      &lt;/a&gt; / &lt;a href="https://github.com/Baralga/baralga" rel="noopener noreferrer"&gt;
        baralga
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Simple and lightweight time tracking for individuals and teams.
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>java</category>
      <category>architecture</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Go for SonarCloud with Github Actions</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Sun, 03 Nov 2019 12:36:00 +0000</pubDate>
      <link>https://dev.to/remast/go-for-sonarcloud-with-github-actions-3pmn</link>
      <guid>https://dev.to/remast/go-for-sonarcloud-with-github-actions-3pmn</guid>
      <description>&lt;h1&gt;
  
  
  Go for SonarCloud with Github Actions
&lt;/h1&gt;

&lt;p&gt;Learn the basics of analyzing a Go project with SonarQube in my post &lt;a href="https://medium.com/red6-es/go-for-sonarqube-ffff5b74f33a" rel="noopener noreferrer"&gt;Go for SonarQube&lt;/a&gt;. In this post I'll show you how to use &lt;a href=""&gt;Github Actions&lt;/a&gt; to analyze your Go project with &lt;a href="https://sonarcloud.io" rel="noopener noreferrer"&gt;SonarCloud&lt;/a&gt;. SonarCloud offers SonarQube as a service.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/remast" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F174171%2F820e2c45-8713-4e15-be64-84b5cc140799.jpeg" alt="remast"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/remast/go-for-sonarqube-4iho" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Go for SonarQube&lt;/h2&gt;
      &lt;h3&gt;Jan Stamer ・ Aug 8 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#codequality&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#architecture&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#cleancode&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Metrics like lines of code or test coverage are great to track and improve the quality of your source code. SonarQube can calculate these metrics for your project and track how they evolve over time. Since SonarQube natively supports Go it's a great fit to calculate metrics fo your Go project. &lt;/p&gt;

&lt;h2&gt;
  
  
  Set up a Build with Github Actions
&lt;/h2&gt;

&lt;p&gt;We start by setting up a basic build pipeline for our Go project using &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;. We use the Github's official Go action &lt;a href="https://github.com/actions/setup-go" rel="noopener noreferrer"&gt;setup-go&lt;/a&gt; for our build. So we create our pipeline for Github Actions in the file &lt;code&gt;.github/workflows/build.yml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Main Workflow&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build, Test and Analyze&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Go&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-go@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;go-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.19'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone Repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Test&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now Github runs our pipeline on every push to the git repository. The pipeline set's up an Go environment, clones the repository and finally builds and tests with &lt;code&gt;make test&lt;/code&gt;. The tests also calculates the code coverage of the tests and save it in &lt;code&gt;bin/cov.out&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Run the SonarCloud Analysis as Step
&lt;/h2&gt;

&lt;p&gt;Now we can add the SonarCloud analysis as step in our pipeline using the &lt;a href="https://github.com/SonarSource/sonarcloud-github-action" rel="noopener noreferrer"&gt;sonarcloud-github-action&lt;/a&gt;. But before that you need to register for SonarCloud. You can use your Github account to sign up. &lt;/p&gt;

&lt;p&gt;The step to add the SonarCloud analysis is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Analyze with SonarCloud&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarsource/sonarcloud-github-action@master&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;SONAR_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SONAR_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The step analyzes our Go code using the &lt;a href="https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/" rel="noopener noreferrer"&gt;sonar-scanner tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The SonarCloud Action needs two environment variables. The first one is &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; which is already provided by Github (see &lt;a href="https://help.github.com/en/github/automating-your-workflow-with-github-actions/virtual-environments-for-github-actions" rel="noopener noreferrer"&gt;Virtual environments for GitHub Actions&lt;/a&gt;). The second one is the &lt;code&gt;SONAR_TOKEN&lt;/code&gt; to authenticate the Github Action with SonarCloud. &lt;/p&gt;

&lt;p&gt;To generate the access token &lt;code&gt;SONAR_TOKEN&lt;/code&gt;  log into SonarCloud. Now click on your profile and then go to 'My Account' and then 'Security'. Or go directly to &lt;a href="https://sonarcloud.io/account/security/" rel="noopener noreferrer"&gt;account/security&lt;/a&gt;. Generate your access token for SonarCloud here. The access token is provided to the build pipeline as a secret environment variable. Go to your repository settings in Github. Then to 'Secrets' and add a new secret with name &lt;code&gt;SONAR_TOKEN&lt;/code&gt; and use the generated SonarCloud access token as value, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2019-11_Go-for-SonarCloud-with-Github-Actions%2Fgithub-action-secrets.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2019-11_Go-for-SonarCloud-with-Github-Actions%2Fgithub-action-secrets.png" alt="Github Repostory Secrets" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our new pipeline to build, test and analyze the source code with SonarCloud is shown below.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Main Workflow&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build, Test and Analyze&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Go&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-go@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;go-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.19'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone Repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Test&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Analyze with SonarCloud&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarsource/sonarcloud-github-action@master&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;SONAR_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SONAR_TOKEN }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Add Code Coverage to SonarCloud
&lt;/h2&gt;

&lt;p&gt;SonarCloud is able to analyze our source code. Yet it's not able to pick up the code coverage of our tests which is stored in the file &lt;code&gt;bin/cov.out&lt;/code&gt;. And this is a bit tricky. The sonar-scanner looks for the code coverage in file &lt;code&gt;/home/runner/work/service_sonar/service_sonar/bin/cov.out&lt;/code&gt;. That's where it is after the tests. The problem is the sonar-scanner tool is executed with docker and mounts the current directory as a volume like &lt;code&gt;docker run --workdir /github/workspace [...] -v "/home/runner/work/service_sonar/service_sonar":"/github/workspace"&lt;/code&gt;. Within the docker run there is no file &lt;code&gt;/home/runner/work/service_sonar/service_sonar/bin/cov.out&lt;/code&gt; but the path of that file within docker is actually &lt;code&gt;/github/workspace/bin/cov.out&lt;/code&gt;. So we need to use that path as &lt;code&gt;sonar.go.coverage.reportPaths&lt;/code&gt; in the SonarQube settings file &lt;code&gt;sonar-project.properties&lt;/code&gt;. The full &lt;code&gt;sonar-project.properties&lt;/code&gt; for Github Actions are shown below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Github organization linked to sonarcloud
sonar.organization=remast

# Project key from sonarcloud dashboard for Github Action, otherwise pick a project key you like
sonar.projectKey=de.red6:service_sonar

sonar.projectName=service_sonar
sonar.projectVersion=1.0.0

sonar.sources=.
sonar.exclusions=**/*_test.go,**/vendor/**,**/testdata/*

sonar.tests=.
sonar.test.inclusions=**/*_test.go
sonar.test.exclusions=**/vendor/**
sonar.go.coverage.reportPaths=/github/workspace/bin/cov.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A live example of the pipeline can be found at &lt;a href="https://github.com/remast/service_sonar/tree/feature/gh-pipeline-simplify" rel="noopener noreferrer"&gt;service_sonar&lt;/a&gt; (branch &lt;code&gt;feature/gh-pipeline-simplify&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  Our project in the SonarCloud Dashboard
&lt;/h2&gt;

&lt;p&gt;After the first SonarCloud analysis you can see the results on the SonarCloud project dashboard shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2019-11_Go-for-SonarCloud-with-Github-Actions%2Fgo-sonarcloud-dashboard.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2019-11_Go-for-SonarCloud-with-Github-Actions%2Fgo-sonarcloud-dashboard.png" alt="SonarCloud Dashboard" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out dashboard of the sample project at &lt;a href="https://sonarcloud.io/dashboard?id=de.red6%3Aservice_sonar" rel="noopener noreferrer"&gt;https://sonarcloud.io/dashboard?id=de.red6%3Aservice_sonar&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Run the SonarCloud Analysis as Job
&lt;/h2&gt;

&lt;p&gt;Currently our pipeline has two main steps. The first step is build and test and the second step is the SonarCloud analysis. In big projects the SonarClould analysis can take up to several minutes. Since steps are executed synchronously one after the other the pipeline can only continue once SonarCloud is done analyzing. But what about our integration tests? Say we want to run some integration tests after the build. We want to give feedback about the integration tests as soon as possible. This means we don't want to wait for the SonarCloud analysis but proceed to the integration tests right after build and test. This is easily possible if we separate out the SonarCloud analysis as a separate job.&lt;/p&gt;

&lt;p&gt;Github Actions runs jobs in a workflow in parallel. So we can split our pipeline in three jobs. The first job is build and test. Then we have a second job to for the SonarCloud analysis and a third job that runs the integration tests. The job to build and test has to run first. After that both the job for the SonarCloud analysis and the integration tests can run in parallel. &lt;/p&gt;
&lt;h3&gt;
  
  
  First pipeline draft
&lt;/h3&gt;

&lt;p&gt;The first draft of our improved pipeline shown below. It has the three jobs &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;sonarCloudTrigger&lt;/code&gt; and &lt;code&gt;integrationTest&lt;/code&gt;. The jobs &lt;code&gt;sonarCloudTrigger&lt;/code&gt; and &lt;code&gt;integrationTest&lt;/code&gt; both depend on the job build which is declared with &lt;code&gt;needs: build&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Main Workflow&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Compile and Test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone Repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup go&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-go@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;go-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.13'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make test&lt;/span&gt;

  &lt;span class="na"&gt;sonarCloudTrigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SonarCloud Trigger&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone Repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Analyze with SonarCloud&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarsource/sonarcloud-github-action@master&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;SONAR_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SONAR_TOKEN }}&lt;/span&gt;

  &lt;span class="na"&gt;integrationTest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Integration Test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo Should run integration tests.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The pipeline is executed the way we wanted. The job &lt;code&gt;build&lt;/code&gt; runs first and after that &lt;code&gt;sonarCloudTrigger&lt;/code&gt; and &lt;code&gt;integrationTest&lt;/code&gt; run in parallel. It has only one flaw though. Do you see it? If you check the logs you will notice that SonarCloud is not able to read the code coverage of the unit tests. SonarCloud looks for the code coverage in the file &lt;code&gt;bin/cov.out&lt;/code&gt;. This file is only present in the &lt;code&gt;build&lt;/code&gt; job but not in the job &lt;code&gt;sonarCloudTrigger&lt;/code&gt;. So we need to transfer the file from one job to the other.&lt;/p&gt;
&lt;h2&gt;
  
  
  Revised pipeline with Code Coverage
&lt;/h2&gt;

&lt;p&gt;To transfer the file &lt;code&gt;bin/cov.out&lt;/code&gt; from the &lt;code&gt;build&lt;/code&gt; job to the &lt;code&gt;sonarCloudTriggerJob&lt;/code&gt; we'll use the actions &lt;a href="https://github.com/actions/upload-artifact" rel="noopener noreferrer"&gt;upload-artifact&lt;/a&gt; and &lt;a href="https://github.com/actions/download-artifact" rel="noopener noreferrer"&gt;download-artifact&lt;/a&gt;. We add the action &lt;code&gt;upload-artifact&lt;/code&gt; to the &lt;code&gt;build&lt;/code&gt; job and &lt;code&gt;download-artifact&lt;/code&gt; to the &lt;code&gt;sonarCloudTriggerJob&lt;/code&gt; job like below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Main Workflow&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Compile and Test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone Repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup go&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-go@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;go-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.13'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;make test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Archive code coverage results&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;code-coverage-report&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bin&lt;/span&gt;

  &lt;span class="na"&gt;sonarCloudTrigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SonarCloud Trigger&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clone Repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Download code coverage results&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/download-artifact@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;code-coverage-report&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bin&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Analyze with SonarCloud&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonarsource/sonarcloud-github-action@master&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;SONAR_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SONAR_TOKEN }}&lt;/span&gt;

  &lt;span class="na"&gt;integrationTest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Integration Test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo Should run integration tests.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A live example of the pipeline can be found at &lt;a href="https://github.com/remast/service_sonar/tree/master" rel="noopener noreferrer"&gt;service_sonar&lt;/a&gt; (branch &lt;code&gt;master&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;
  
  
  Add a SonarCloud Badge
&lt;/h2&gt;

&lt;p&gt;We can add a SonarCloud badge to our project to quickly show the SonarCloud status of our project from within the readme. To create SonarCloud badge go to your SonarCloud project dashboard and click 'Get project badges'. You can choose between three badges as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2019-11_Go-for-SonarCloud-with-Github-Actions%2Fsonarcloud-badges.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fremast%2Fremast.github.io%2Fraw%2Fmaster%2Fposts%2F2019-11_Go-for-SonarCloud-with-Github-Actions%2Fsonarcloud-badges.png" alt="SonarCloud Badges" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;Now you have learned how to analyse Go code using SonarCloud from a Github Action pipeline. By using a separate job for the SonarCloud analysis we are able to run the  time-consuming analysis in parallel to other important tasks like integration tests or deployment.&lt;/p&gt;

&lt;p&gt;All code is provided as a running example in the Github project &lt;a href="https://github.com/remast/service_sonar" rel="noopener noreferrer"&gt;service_sonar&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/remast" rel="noopener noreferrer"&gt;
        remast
      &lt;/a&gt; / &lt;a href="https://github.com/remast/service_sonar" rel="noopener noreferrer"&gt;
        service_sonar
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Example for analyzing Go code with SonarQube (including Github Action).
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>go</category>
      <category>codequality</category>
      <category>architecture</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>The Coders Bucket List</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Tue, 22 Oct 2019 18:04:54 +0000</pubDate>
      <link>https://dev.to/remast/the-coders-bucket-list-138m</link>
      <guid>https://dev.to/remast/the-coders-bucket-list-138m</guid>
      <description>&lt;p&gt;A bucket list is a list of things you ought to do before you &lt;a href="https://en.wikipedia.org/wiki/Kick_the_bucket" rel="noopener noreferrer"&gt;&lt;em&gt;kick the bucket&lt;/em&gt;&lt;/a&gt; and die. Here's a bucket list for every coder out there. Check it out and tackle them one at a time!&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile your own Linux Kernel
&lt;/h2&gt;

&lt;p&gt;The linux kernel is the heart of the Linux operating system and is open source. Compile your own linux kernel to get a deeper understanding of how linux, open source software and the kernel itself work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up a Build and Deployment Pipeline
&lt;/h2&gt;

&lt;p&gt;Set up your own pipeline to build and deploy your code. The pipeline should compile your code, create an artifact like a docker container and deploy it on a remote machine. You can build the pipeline in &lt;a href="https://jenkins.io/" rel="noopener noreferrer"&gt;Jenkins&lt;/a&gt;, &lt;a href="https://docs.gitlab.com/ee/ci/" rel="noopener noreferrer"&gt;Gitlab CI&lt;/a&gt;, &lt;a href="https://travis-ci.org/" rel="noopener noreferrer"&gt;Travis CI&lt;/a&gt; or using &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mentor a Junior Dev
&lt;/h2&gt;

&lt;p&gt;Mentor a junior developer will teach both you and your mentee a lot. You can share your knowledge and give your mentee a great start in the job. You'll see that also you will benefit by looking at things from a different angle and explaining things you've been using and doing for quite some time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install and run stuff on FreeBSD
&lt;/h2&gt;

&lt;p&gt;Install a unix distribution like &lt;a href="https://www.freebsd.org" rel="noopener noreferrer"&gt;FreeBSD&lt;/a&gt; on a machine and run some stuff on it. Real unixes are quite different from linux as you will notice. Yet unixes are great and very stable server operating systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give a Talk
&lt;/h2&gt;

&lt;p&gt;Share experiences or knowledge with others by giving a talk. This talk can be for your team only, within your company of even at a conference. Think carefully about what you want to tell and how. Learning and practicing&lt;br&gt;
to give a talk will greatly improve your communication skills.&lt;/p&gt;
&lt;h2&gt;
  
  
  Contribute to Open Source
&lt;/h2&gt;

&lt;p&gt;Contributing to an Open Source project that you like. You can contribute not only code but also documentation, translations or tests. Some projects have issues that are specially suited for newbies. E.g. in Spring these issues are tagged &lt;a href="https://github.com/spring-projects/spring-framework/labels/status%3A%20ideal-for-contribution" rel="noopener noreferrer"&gt;ideal-for-contribution&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Give a Training
&lt;/h2&gt;

&lt;p&gt;Give a training in our outside your company. Prepare the training yourself with background information and hands on practical excercises and tasks. If you can give the training more than once - even better. You'll experience&lt;br&gt;
that every training is different and all participants will experience the training differently.&lt;/p&gt;
&lt;h2&gt;
  
  
  Write a Compiler
&lt;/h2&gt;

&lt;p&gt;Compilers is where program languages start. Write you own little compiler and you will gain lots of insights into the inner workings of programming languages.&lt;/p&gt;
&lt;h2&gt;
  
  
  Learn a Functional Programming Language
&lt;/h2&gt;

&lt;p&gt;Learning to program in a pure functional programming lanuage like &lt;a href="https://www.haskell.org/" rel="noopener noreferrer"&gt;Haskell&lt;/a&gt; or &lt;a href="https://elm-lang.org/" rel="noopener noreferrer"&gt;Elm&lt;/a&gt; will change the way you think about programming. So check it out even it won't become your primary language.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bring a Website to Production
&lt;/h2&gt;

&lt;p&gt;Code a website using plain HTML and CSS and bring it to production. Register a domain name and make your website available under that domain. Even better use web server like &lt;a href="https://httpd.apache.org/" rel="noopener noreferrer"&gt;Apache&lt;/a&gt;, &lt;a href="https://www.nginx.com/" rel="noopener noreferrer"&gt;nginx&lt;/a&gt; or &lt;a href="https://caddyserver.com/" rel="noopener noreferrer"&gt;Caddy&lt;/a&gt; to serve the website.&lt;/p&gt;
&lt;h2&gt;
  
  
  Develop a mobile app (and release it)
&lt;/h2&gt;

&lt;p&gt;Develop your own mobile application for Android or iOS and release it in the app store. Make your app communicate with backend services and use device functionalities like geolocation via GPS.&lt;/p&gt;
&lt;h2&gt;
  
  
  Learn to use vim and emacs
&lt;/h2&gt;

&lt;p&gt;The classic text editors are &lt;a href="https://www.vim.org/" rel="noopener noreferrer"&gt;vim&lt;/a&gt; and &lt;a href="https://www.gnu.org/software/emacs/" rel="noopener noreferrer"&gt;emacs&lt;/a&gt;. So take the time to learn basic text editing in both &lt;a href="https://www.vim.org/" rel="noopener noreferrer"&gt;vim&lt;/a&gt; and &lt;a href="https://www.gnu.org/software/emacs/" rel="noopener noreferrer"&gt;emacs&lt;/a&gt;. Once mastered it's a skill you can use for the next 30 years. &lt;/p&gt;
&lt;h2&gt;
  
  
  Mess up Production real bad
&lt;/h2&gt;

&lt;p&gt;When you develop production code it's only a matter of time. One day you will write code that messes up production. But don't you worry we've all been there and we all make mistakes. So fix it, learn from and grow from it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fix Production on Pager Duty
&lt;/h2&gt;

&lt;p&gt;You are on pager duty and shit happens. Maybe some hardware breaks down, a 3rd party service is not available any more or the configuration is messed up. There will be a day when you dig into the issue and find the root cause. Hang into it and fix production. Enjoy the feeling when everything is running smoothly again.&lt;/p&gt;
&lt;h2&gt;
  
  
  Write a JavaScript Single Page Application
&lt;/h2&gt;

&lt;p&gt;Single Page JavaScript Applications (SPAs) are one very important way to develop a web frontend. Write a JavaScript SPA application to get to know how SPAs are built and distributed. You can use a JavaScript framework like &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt;, &lt;a href="https://angular.io/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; or &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; to get you started.&lt;/p&gt;
&lt;h2&gt;
  
  
  Write a Server Rendered App
&lt;/h2&gt;

&lt;p&gt;Building a web frontend as a server rendered app is a classic but still very valid approach to develop a web frontend. So write a server rendered web frontend in the language of your choice. For PHP you might use &lt;a href="https://laravel.com/docs/5.8/blade" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt;, for Java &lt;a href="https://spring.io/guides/gs/serving-web-content/" rel="noopener noreferrer"&gt;Spring Boot &amp;amp; MVC&lt;/a&gt; or &lt;a href="https://gobuffalo.io" rel="noopener noreferrer"&gt;Buffalo&lt;/a&gt; for Go.&lt;/p&gt;
&lt;h2&gt;
  
  
  Learn Shell Scripting
&lt;/h2&gt;

&lt;p&gt;Shell scripting is quick way to script and automate tasks on any Linux and Unix machine. Learn to write a script for the &lt;a href="https://www.gnu.org/software/bash/" rel="noopener noreferrer"&gt;Bash&lt;/a&gt; shell. Make use of classic tools for shell scripting like &lt;code&gt;awk&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt; or &lt;code&gt;cut&lt;/code&gt;. If you want to top it off write your script in &lt;a href="https://www.vim.org/" rel="noopener noreferrer"&gt;vim&lt;/a&gt; or &lt;a href="https://www.gnu.org/software/emacs/" rel="noopener noreferrer"&gt;emacs&lt;/a&gt; (see above).&lt;/p&gt;
&lt;h2&gt;
  
  
  Hack in a Capture the Flag Contest
&lt;/h2&gt;

&lt;p&gt;Improve your security skills and learn how to hack in a capture the flag contest. Read all about it here:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/atan" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F47043%2Ff167c114-56bc-4967-9037-95e9fd3c31b9.jpg" alt="atan"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/atan/what-is-ctf-and-how-to-get-started-3f04" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;What is CTF and how to get started!&lt;/h2&gt;
      &lt;h3&gt;atan ・ Mar 28 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#security&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ctf&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>beginners</category>
      <category>career</category>
    </item>
    <item>
      <title>Go for the REST</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Fri, 06 Sep 2019 18:29:40 +0000</pubDate>
      <link>https://dev.to/remast/go-for-the-rest-1jp9</link>
      <guid>https://dev.to/remast/go-for-the-rest-1jp9</guid>
      <description>&lt;p&gt;The Go programming language is a great fit for RESTful web applications. Picking the right Go web framework to start with is not an easy task. Lucky enough it is a task solved already. Pick the Go web framework &lt;a href="https://gobuffalo.io" rel="noopener noreferrer"&gt;buffalo&lt;/a&gt; and off you go. Not convinced yet? Learn how to build a RESTful web application with &lt;a href="https://gobuffalo.io" rel="noopener noreferrer"&gt;buffalo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gobuffalo.io" rel="noopener noreferrer"&gt;Buffalo&lt;/a&gt; is a whole ecosystem to develop web applications in Go. Buffalo combines routing, templating and testing to build web applications based on the famous &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" rel="noopener noreferrer"&gt;model-view-controller pattern&lt;/a&gt;. The foundation is a powerful tooling with hot reload, a generator for views and controller and tools for common tasks like compressing JavaScript or database migration. Buffalo combines existing libraries like the Gorilla web toolkit with best practices of Go web development. With buffalo comes a uniform and consistent project structure covering packages and directories up until handling the database session. So let's get started.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installing Buffalo
&lt;/h1&gt;

&lt;p&gt;We'll use the new &lt;a href="https://blog.golang.org/using-go-modules" rel="noopener noreferrer"&gt;Go modules&lt;/a&gt; for dependency management. So let's activate that using the environment variable &lt;code&gt;GO111MODULE=on&lt;/code&gt;. Now we can install buffalo with &lt;code&gt;go get -u -v github.com/gobuffalo/buffalo/buffalo&lt;/code&gt;. Executing the command &lt;code&gt;buffalo&lt;/code&gt; in your shell should display the help.&lt;/p&gt;

&lt;h1&gt;
  
  
  Create and run the RESTful web application
&lt;/h1&gt;

&lt;p&gt;Now we create our first buffalo RESTful web application named &lt;code&gt;rowdy&lt;/code&gt;. The command &lt;code&gt;buffalo new rowdy --api&lt;/code&gt; creates a new RESTful buffalo web application (without frontend) in the directory &lt;code&gt;rowdy&lt;/code&gt;. We can run the application with the command &lt;code&gt;buffalo dev&lt;/code&gt; (from directory &lt;code&gt;rowdy&lt;/code&gt;). The application is available at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;. But wait, that doesn't work! The generated application needs a running database. so we start a PostgreSQL database with &lt;code&gt;docker run --name rowdy_db -e POSTGRES_PASSWORD=postgres -d postgres&lt;/code&gt;. Now you should be able to start the application and access the REST API under the web root saying &lt;code&gt;"Welcome to Buffalo"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can keep the application running while you develop. Buffalo will automatically pick up changes in sources and rebuild and restart the application as needed.&lt;/p&gt;

&lt;h1&gt;
  
  
  Guide through the App
&lt;/h1&gt;

&lt;p&gt;Entry point of the buffalo application is the &lt;code&gt;main.go&lt;/code&gt; in the root directory of our application. The main.go is the main package of the application and starts the application by executing the method &lt;code&gt;Serve&lt;/code&gt; of the buffalo struct &lt;a href="https://godoc.org/github.com/gobuffalo/buffalo#App" rel="noopener noreferrer"&gt;&lt;code&gt;buffalo.App&lt;/code&gt;&lt;/a&gt;. The buffalo app itself is created in the &lt;code&gt;app.go&lt;/code&gt; which is in the package actions.&lt;/p&gt;

&lt;p&gt;The app.go is where the music plays. In the &lt;code&gt;app.go&lt;/code&gt; all routes and middlewares are registered. For every route an action is registered. An action is the controller layer of the MVC pattern. For the moment we only have one action which is the &lt;code&gt;HomeHandler&lt;/code&gt;. With &lt;code&gt;app.GET("/", HomeHandler)&lt;/code&gt; the action HomeHandler is registered in the app.go for the path &lt;code&gt;/&lt;/code&gt;. The &lt;code&gt;HomeHandler&lt;/code&gt; itself is declared in home.go in the package actions, and the associated test is in &lt;code&gt;home_test.go&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The package model is for the model layer of MVC. Buffalo assumes the model layer is the persistence layer of the application running against a relational database like postgres. This model layer is based on  buffalo pop, a active record inspired persistence layer for Go.&lt;/p&gt;

&lt;p&gt;The directory migrations is all about maintaining the schema of the relational database. Here scripts for the database migration framework &lt;a href="https://gobuffalo.io/en/docs/db/fizz" rel="noopener noreferrer"&gt;fizz&lt;/a&gt; are stored. But we'll get to that later.&lt;/p&gt;

&lt;p&gt;Then there are the directories fixtures, config and grifts. Fixtures are scripts to create database content for tests. Config is for the configuration of the buffalo code generator. Grifts are small scripts to automate common tasks like listing all routes.&lt;/p&gt;

&lt;p&gt;To complete our guide we look at the generated configuration files. The most important config file of our application is the database.yml with the database credentials for several environments. Then there is the Dockerfile to create a docker container of our app.&lt;/p&gt;

&lt;h1&gt;
  
  
  Create a Health Check Action
&lt;/h1&gt;

&lt;p&gt;Now let's create our first action, a health check at route &lt;code&gt;/health/check&lt;/code&gt;. We generate the skeleton of our health check action using the buffalo code generator by running &lt;code&gt;buffalo generate action health check --skip-template&lt;/code&gt;. That generated an action with name &lt;code&gt;HealthCheck&lt;/code&gt;. The first parameter of the generator command is the name of the action and the second parameter check is the name of the handler. Since we build a RESTful API we don't need a HTML template for our action and suppress generating one with the parameter &lt;code&gt;--skip-template&lt;/code&gt;. Buffalo created the files &lt;code&gt;health.go&lt;/code&gt; and &lt;code&gt;health_test.go&lt;/code&gt; in the directory actions. The generator also registered our new action for the path &lt;code&gt;/health/check&lt;/code&gt; in the &lt;code&gt;app.go&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A buffalo action needs to implement the interface &lt;a href="https://godoc.org/github.com/gobuffalo/buffalo#Handler" rel="noopener noreferrer"&gt;&lt;code&gt;buffalo.Handler&lt;/code&gt;&lt;/a&gt;. The terms action and handler are both synonymously used for the controller layer of the MVC pattern. A look at the &lt;code&gt;home.go&lt;/code&gt; shows the generated code:&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;HealthCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;buffalo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"health/check.html"&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 generated handler tries to render the template &lt;code&gt;health/check.html&lt;/code&gt; as HTML. Since we build a RESTful API we don't have templates so this can't work. We change the implementation to &lt;code&gt;c.Render(200, r.String("Up and running!"))&lt;/code&gt; so that it returns a plain text string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HealthCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;buffalo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&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;"Up and running!"&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;h1&gt;
  
  
  Test the Health Check
&lt;/h1&gt;

&lt;p&gt;Now we need to fix the test for our health check. The whole buffalo application is available it the test. In the test you can run requests against the application or even access the database it's running against of the HTTP session.&lt;/p&gt;

&lt;p&gt;To test the health check we run request path &lt;code&gt;/health/check&lt;/code&gt; and verify the HTTP status code. The code to do that is:&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;actions&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;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ActionSuite&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Test_Health_Check&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/health"&lt;/span&gt;&lt;span class="p"&gt;)&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;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;as&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Up and running"&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;h1&gt;
  
  
  More about Actions and Routes
&lt;/h1&gt;

&lt;p&gt;When configuring routes you can use placeholders and regular expressions in the path like &lt;code&gt;app.GET("/account/{category}/{id:[0-9]+}", AccountHandler)&lt;/code&gt;. Since that's base on the Gorilla web toolkit you can make full use of the Gorilla multiplexer.&lt;/p&gt;

&lt;p&gt;In the handler itself you have full access to the &lt;a href="https://godoc.org/github.com/gobuffalo/buffalo#Context" rel="noopener noreferrer"&gt;&lt;code&gt;buffalo.Context&lt;/code&gt;&lt;/a&gt;. With the buffalo context you can render JSON or HTML and access path and query parameters with them methods &lt;code&gt;c.Params()&lt;/code&gt; and &lt;code&gt;c.Param(string)&lt;/code&gt;. You can also acess the logger and log health check requests with &lt;code&gt;c.Logger().Info("Health checked by: %v", c.Request().Host)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To get an overview of all registered routes use the command &lt;code&gt;buffalo routes&lt;/code&gt; which prints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;METHOD | PATH           | ALIASES | NAME            | HANDLER
------ | ----           | ------- | ----            | -------
GET    | /              |         | rootPath        | rowdy/actions.HomeHandler
GET    | /health/check/ |         | healthCheckPath | rowdy/actions.HealthCheck
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CRUD Resources
&lt;/h2&gt;

&lt;p&gt;To make it easy to develop CRUD functionality buffalo has resources. A buffalo resource always contains the actions Create, Show, Update, Destroy and List with standardized paths in the router. Resources are always RESTful and never use templates.&lt;/p&gt;

&lt;p&gt;Now we create a resource to manage concerts with &lt;code&gt;buffalo generate resource concert&lt;/code&gt;. Buffalo created several files for us. The implemntation of the concert resource in the files &lt;code&gt;concert.go&lt;/code&gt; in the package actions, along with the tests in &lt;code&gt;concert_test.go&lt;/code&gt;. A database mapping for pop in &lt;code&gt;concert.go&lt;/code&gt; in the package models including test. And last but not least in the directory migrations two fizz scripts to create a table for the concerts in our database schema. The concerts resources is registered in the &lt;code&gt;app.go&lt;/code&gt; using &lt;code&gt;app.Resource("/concerts", ConcertsResource{})&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Looking at the output of buffalo routes we see all the routes of our new concert resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;METHOD | PATH                    | ALIASES | NAME            | HANDLER
------ | ----                    | ------- | ----            | -------
GET    | /                       |         | rootPath        | rowdy/actions.HomeHandler
GET    | /concerts/              |         | concertsPath    | rowdy/actions.ConcertsResource.List
POST   | /concerts/              |         | concertsPath    | rowdy/actions.ConcertsResource.Create
GET    | /concerts/{concert_id}/ |         | concertPath     | rowdy/actions.ConcertsResource.Show
PUT    | /concerts/{concert_id}/ |         | concertPath     | rowdy/actions.ConcertsResource.Update
DELETE | /concerts/{concert_id}/ |         | concertPath     | rowdy/actions.ConcertsResource.Destroy
GET    | /health/check/          |         | healthCheckPath | rowdy/actions.HealthCheck
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's now look into the generated handler method &lt;code&gt;Show&lt;/code&gt;. We see that buffalo gets the database connection from the buffalo context with &lt;code&gt;c.Value("tx").(*pop.Connection)&lt;/code&gt;. Then buffalo loads the concert model from the database using pop. The id of the concert model is provided as a path parameter. Finally the loaded concert model is returned with &lt;code&gt;c.Render(200, r.Auto(c, concert))&lt;/code&gt;. Depending on the negotiated content-type this is either as JSON or as XML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// GET /concerts/{concert_id}&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;v&lt;/span&gt; &lt;span class="n"&gt;ConcertsResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;buffalo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Get the DB connection from the context&lt;/span&gt;
    &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tx"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&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;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"no transaction found"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Allocate an empty Concert&lt;/span&gt;
    &lt;span class="n"&gt;concert&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;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Concert&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="c"&gt;// To find the Concert the parameter concert_id is used.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"concert_id"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Auto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;concert&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;h2&gt;
  
  
  Error Handling
&lt;/h2&gt;

&lt;p&gt;Handling errors properly can be tricky. But buffalo has you covered. Errors generally occur in handlers. Handlers have two options of dealing with them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Return a normal Go error from the handler like &lt;code&gt;errors.New("Boom!")&lt;/code&gt;. The application then returns HTTP status code 500 for internal server error.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the bufallo context method Error to handle like &lt;code&gt;return context.Error(501, errors.New("That blew up!"))&lt;/code&gt;. That way the applications returns the custom status code 501.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Either way the application keeps running and the error is logged and returned either as JSON or XML. If buffalo runs in dev mode (environment &lt;code&gt;variable GO_ENV="development"&lt;/code&gt; or start with &lt;code&gt;buffalo dev&lt;/code&gt;) this will contain a stacktrace of the error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Middlewares
&lt;/h2&gt;

&lt;p&gt;Buffalo applications feature many best practices in Go web development. This is mainly featured by various middleware. A middleware is code that runs befor or after a HTTP handler (in buffalo called action). Middlewares are a general concept of Go web development. A good read about the concept of middleware is &lt;a href="https://www.alexedwards.net/blog/making-and-using-middleware" rel="noopener noreferrer"&gt;Making and Using HTTP Middleware&lt;/a&gt; by Alex Edwards.&lt;/p&gt;

&lt;p&gt;Buffalo comes with lots of usefule middlewares integrated into the &lt;a href="https://godoc.org/github.com/gobuffalo/buffalo#App" rel="noopener noreferrer"&gt;&lt;code&gt;buffalo.App&lt;/code&gt;&lt;/a&gt; right from the start. E.g. middleware that prevents your app from crashing after a panic or an error. In our generated app middleware is registered in &lt;code&gt;actions/app.go&lt;/code&gt;. One example is &lt;code&gt;app.Use(forceSSL)&lt;/code&gt; which registers a middleware that redirects HTTP requests to HTTPS.&lt;/p&gt;

&lt;p&gt;It's also possible to skip middleware for specific routes. We could use this to skip authentication middleware for our health check route. The command &lt;code&gt;buffalo task middleware&lt;/code&gt; shows the registered middlewares for every route.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;A buffalo app is configured using environment variables as proposed in &lt;a href="https://12factor.net/config" rel="noopener noreferrer"&gt;the twelve-factor app&lt;/a&gt;. The configuration is powered by the buffalop package &lt;a href="https://github.com/gobuffalo/envy" rel="noopener noreferrer"&gt;envy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are predefined environment variables like &lt;code&gt;GO_ENV&lt;/code&gt; for the current environment (e.g. development, test, production) or &lt;code&gt;HOST&lt;/code&gt; (&lt;code&gt;localhost&lt;/code&gt;) and &lt;code&gt;PORT&lt;/code&gt; (3000). You can also use custom variables. You can use an optional environment variable with &lt;code&gt;envy.Get("CUSTOM_SETTING", "default-value")&lt;/code&gt;. Or a mandatory variable with &lt;code&gt;envy.MustGet("MY_REQUIRED_OPTION")&lt;/code&gt; which results in an error if the variable is not set.&lt;/p&gt;

&lt;p&gt;You can also read environment variables from the file &lt;code&gt;.env&lt;/code&gt;. Buffalo looks for a file named &lt;code&gt;.env&lt;/code&gt; in the current directory and evaluates it. This nicely integrates with &lt;a href="https://direnv.net/" rel="noopener noreferrer"&gt;direnv&lt;/a&gt; if you create a &lt;code&gt;.envrc&lt;/code&gt; with only the line &lt;code&gt;dotenv&lt;/code&gt; (see &lt;a href="https://github.com/direnv/direnv/issues/284" rel="noopener noreferrer"&gt;&lt;code&gt;.env&lt;/code&gt; files&lt;/a&gt;). You can use this to have buffalo read your local development settings which of course you should never check in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugins
&lt;/h2&gt;

&lt;p&gt;Buffalo can be extended using plugins. The database framework pop is implemented as a buffalo plugin. There are also plugins for &lt;a href="https://toolkit.gobuffalo.io/tools/69219770-87c4-4e53-9b6e-92f81ab819e4/" rel="noopener noreferrer"&gt;kubernetes&lt;/a&gt; or &lt;a href="https://toolkit.gobuffalo.io/tools/d299aa2d-03be-4df6-bd05-9b19d3f19ae6/" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;. The buffalo website contains a &lt;a href="https://toolkit.gobuffalo.io/tools?topic=plugin" rel="noopener noreferrer"&gt;list of available plugins&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the App
&lt;/h2&gt;

&lt;p&gt;To build the app run &lt;code&gt;buffalo build&lt;/code&gt;. Buffalo compiles the app and creates a standalone binary &lt;code&gt;rowdy&lt;/code&gt; in the directory &lt;code&gt;build&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up the REST
&lt;/h2&gt;

&lt;p&gt;We learned how to build a RESTful application with the buffalo framework that adheres to the MVC pattern. The model layer consists of structs mapped against a PostgreSQL database using pop. Actions and resources make up the controller layer. We created a simple health check action and a CRUD resource for concerts. We have not used the view layer yet since all we need is serializing structs to XML or JSON. We learned how to handle error, how to deal with configuration and how to run a production build in the CI environment.&lt;/p&gt;

&lt;p&gt;Buffalo comes with a uniform and consistent structure for web applications in go, follows best practices of Go web development and covers the full lifecycle from development to production.&lt;/p&gt;

&lt;p&gt;Yet there's still so much that we could't cover. Buffalo has a lot to offer to build frontends. Or you can use buffalos tasks or background workers. All this is covered by the great &lt;a href="https://gobuffalo.io/en/docs/index/" rel="noopener noreferrer"&gt;buffalo documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And of course stay tuned because I'll spread more buffalo love here soon!&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>microservices</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Soft Coder / 3x3 des Daily Standup</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Mon, 26 Aug 2019 19:22:33 +0000</pubDate>
      <link>https://dev.to/remast/soft-coder-3x3-des-daily-standup-4p0p</link>
      <guid>https://dev.to/remast/soft-coder-3x3-des-daily-standup-4p0p</guid>
      <description>&lt;p&gt;Egal ob Kanban oder Scrum, täglich grüßt das Daily Standup. Das Team hat 15 Minuten, um die wichtigsten Informationen von gestern und heute auszutauschen. Du hast 30 Sekunden. Nutze sie. &lt;/p&gt;

&lt;p&gt;Das folgende 3x3 des Daily Standup hilft Dir dabei. Mit 9 Tipps zum wichtigsten Meeting der agilen Entwicklung.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bereite Dich vor
&lt;/h2&gt;

&lt;p&gt;Vorbereitung ist alles, auch beim Daily Standup. Also bereite Dich vor. Diese 3 Dinge helfen Dir dabei:&lt;/p&gt;

&lt;h3&gt;
  
  
  #1 Komme pünktlich
&lt;/h3&gt;

&lt;p&gt;Komme pünktlich. Nichts ist ärgerlicher als 10 Leute die 5 Minuten auf eine Person warten müssen, die zu spät kommt. Jeden Morgen. Also komme pünktlich. Startet das Daily um 10:00 Uhr setze Dir eine Erinnerung auf 9:55 Uhr. Dann hast Du 5 Minuten, um einen Kaffee zu holen, auf die Toilette zu gehen oder einfach nur um Dich zu sammeln. Um Punkt 10 Uhr stehst Du bereit und der Rest des Teams auch. Dann kann‘s direkt losgehen und Ihr seid auch pünktlich um 10:15 Uhr durch.&lt;/p&gt;

&lt;h3&gt;
  
  
  #2 Überlege was Du sagen willst
&lt;/h3&gt;

&lt;p&gt;Überlege Dir was Du sagen willst. 30 Sekunden für 1 Tag Arbeit ist wenig. Also überlege Dir vorab was Du sagen willst und was nicht. Am wichtigsten sind die Basics des Daily Standup. Also woran hast Du gestern gearbeitet,  woran arbeitest Du heute und was behindert Dich gerade. Aber denke auch an andere Dinge wie Deinen Urlaub nächste Woche. Mach Dir einen Spickzettel mit Notizen falls Dir das hilft an alles zu Denken was Du sagen willst.&lt;/p&gt;

&lt;h3&gt;
  
  
  #3 Kopf frei fürs Daily
&lt;/h3&gt;

&lt;p&gt;Löse Dich von dem woran Du gerade noch gearbeitet hast. So hast Du den Kopf frei fürs Daily und kannst Dich voll auf Dich und Deine Team Mitglieder konzentrieren. Lass doch Dein Handy am Platz, die nächsten 15 Minuten brauchst Du es nicht. Sei präsent und wachsam im Daily Standup. Dein Team weiß das zu schätzen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringe Deinen Inhalt unter
&lt;/h2&gt;

&lt;p&gt;In Deinen 30 Sekunden musst Du Deinen Inhalt unterbringen. 30 Sekunden, einmal und am Stück. Für Dich. Nutze diese 30 Sekunden. Informiere das Team darüber was Du gestern getan hast, und was heute ansteht. Halte alle über Problem, Fragen und Entscheidungen auf dem Laufenden. Dazu musst Du Dich fokussieren, folgende 3 Tipps helfen Dir dabei:&lt;/p&gt;

&lt;h3&gt;
  
  
  #4 Gib einen aussagekräftigen Status.
&lt;/h3&gt;

&lt;p&gt;Gib einen aussagekräftigen Status. Sage was Du getan hast und welchen Status Du damit erreicht hast. Sage konkret was gelaufen ist, aber ohne Details. Lass Ticket Nummern weg, wenn Sie nicht allen geläufig sind. Vermeide Phrasen und Füllwörter sowie schwammige Aussagen. Zum Beispiel: „Gestern habe ich die DDL Skripte zur Erweiterung der Tabelle UMSATZ um die Spalte UUID erstellt. Heute morgen habe ich die fertigen DDL Skripte auf der Testdatenbank cd34 eingespielt.“&lt;/p&gt;

&lt;h3&gt;
  
  
  #5 Sage konkret was Deine nächsten Schritte sind.
&lt;/h3&gt;

&lt;p&gt;Sage konkret was Deine nächsten Schritte sind. Arbeite heute an den wichtigsten nächsten Schritten, um Deinen Task zu erledigen. Sage konkret welche Schritte das sind. Also „Nach dem Daily analysiere ich den Fehler bei der IBAN Prüfung aus der Fast Lane. Heute Nachmittag mache ich das Review der Datenbank Änderung von Michael.“ Beziehe Dich morgen wieder auf diese Aussagen. Dann sieht das Team immer wo Du stehst und was Du noch vor Dir hast.&lt;/p&gt;

&lt;h3&gt;
  
  
  #6 Sprich offene Fragen und Entscheidungen an.
&lt;/h3&gt;

&lt;p&gt;Sprich offene Fragen und Entscheidungen an. Sind noch Fragen oder Entscheidungen offen die Dich behindern, führe aktiv Lösungen und Entscheidungen herbei. „Der Name des Datenbank Schemas ist noch unklar. Das klären wir heute um 11 Uhr gemeinsam, im Termin mit dem Architekten und einem Datenbank Admin.“ Nimm Dir am Morgen Zeit, um einen Termin für eine Entscheidung zu organisieren oder schreibe dem Fachbereich eine E-Mail mit Deinen Fragen. Erledige diese Dinge vor dem Standup. Dann weiß das Team im Standup das Du alles in die Wege geleitet hast um die Entscheidung herbeizuführen. Dann weiß das Team im Standup das Du die Entscheidung auf den Weg gebracht hast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Achte auf Deine Sprache
&lt;/h2&gt;

&lt;p&gt;Nutze die Sprache, um Dich zu fokussieren und Deine Inhalte rüberzubringen. Es hängt von Deiner Sprache ab ob Deine Inhalte beim Team ankommen oder nicht. Hier drei handfeste Tipps, um Deine Sprache im Daily zu verbessern:&lt;/p&gt;

&lt;h3&gt;
  
  
  #7 Mache kurze, knappe Sätze.
&lt;/h3&gt;

&lt;p&gt;Mache kurze und knappe Sätze. Sage nicht zu viel auf einmal. „Ich habe das Review der SQL Query gemacht. Und den Merge Request in den master übernommen. Jetzt habe ich wieder Luft. Ich schnappe mir gleich ein neues Ticket.“&lt;/p&gt;

&lt;h3&gt;
  
  
  #8 Sprich aktiv und konkret
&lt;/h3&gt;

&lt;p&gt;Sprich aktiv und konkret. Sage was Du tun wirst und wann Du es tun wirst. Formuliere immer so das klar ist was zu tun ist und wer das tut. Bestenfalls noch bis wann das getan ist. „Ich schreibe noch einen Unit Test fürs Löschen der Überweisung. Heute Nachmittag werde ich damit fertig.“ Oder „Ich bin auf Angela aus dem QA Team zugegangen. Sie wird den Test bis Ende der Woche durchführen.“&lt;/p&gt;

&lt;h3&gt;
  
  
  #9 Sprich deutlich und mache Pausen.
&lt;/h3&gt;

&lt;p&gt;Sprich deutlich und mache Pausen. Gerade wenn die Zeit knapp ist: Lass Dir Zeit beim Sprechen und mache Pausen. Konzentriere Dich auf die wesentlichen Informationen. Dann hast Du auch in 30 Sekunden genug Zeit langsam und deutlich zu sprechen. „Ich habe gestern Nachmittag das Review abgeschlossen.  Heute kümmere ich mich um den Vorfall aus Produktion.“&lt;/p&gt;

&lt;h2&gt;
  
  
  Daily Standup, Daily Practice
&lt;/h2&gt;

&lt;p&gt;Nutze diese 9 Tipps für Dich und Dein Team. Arbeite an Dir Tag für Tag, Daily für Daily. Betrachte das Daily Standup als täglichen Elevator Pitch. Diesen Elevator Pitch hältst Du jeden Tag. Mache den Elevator Pitch jeden Tag ein kleines Stück besser. Probiere mal etwas Neues aus und experimentiere. Finde heraus was Dir liegt, und was für Dich funktioniert. Wage Dich dabei aus Deiner Komfortzone heraus. Probiere etwas aus was Dir schwer fällt oder für Dich neu ist.&lt;/p&gt;

&lt;p&gt;Gibt es jemand im Team zu dem Du einen persönlichen Draht hast? Frage ob die Person Dir Feedback geben kann. Oder Ihr macht das gegenseitig. Beziehe Dein Team ein und bitte  es in der Retro um Feedback.&lt;/p&gt;

&lt;p&gt;So lernst Du jeden Tag etwas dazu. Was Du dazu lernst hilft Dir nicht nur im Daily Standup sondern in vielen beruflichen und privaten Situationen.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dieser Artikel erschien ursprünglich auf &lt;a href="https://medium.com/@remast/softcoder-001-dailystandup-adcac2b4361e" rel="noopener noreferrer"&gt;medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>german</category>
      <category>agile</category>
      <category>career</category>
    </item>
    <item>
      <title>Wir schreiben Code</title>
      <dc:creator>Jan Stamer</dc:creator>
      <pubDate>Sat, 10 Aug 2019 15:10:34 +0000</pubDate>
      <link>https://dev.to/remast/wir-schreiben-code-3h92</link>
      <guid>https://dev.to/remast/wir-schreiben-code-3h92</guid>
      <description>&lt;p&gt;Wir Software Entwickler lesen und schreiben viel. Aber unser Genre ist nicht Belletristik und nicht Liebesromane. Wir lesen Code. In vielen Sprachen. Wir lesen und schreiben XML, SQL, Java oder JavaScript. Der eine bevorzugt Java, die andere PHP. Wenn wir schreiben sind wir genau und präzise, das müssen wir. Jedes Wort ist wichtig. Auch einzelne Zeichen können entscheiden über Gewinn oder Verlust, manchmal auch über Tod oder Leben. Deswegen müssen wir genau sein, genau schreiben ohne Missverständnisse oder Kompromisse zuzulassen.&lt;/p&gt;

&lt;p&gt;Wie ein Richter in seiner Urteilsbegründung müssen wir eine Aufgabe auseinandernehmen, zerpflücken, und von allen Seiten betrachten. Was für den Richter Verordnungen und Paragraphen sind, sind für uns Anforderungen und technische Rahmenbedingungen. Der Richter stützt sich auf Gesetze, wo es keine Gesetze gibt, kann er nicht richten. Wir stützen uns auf Anforderungen und technische Rahmenbedingungen. Wir können keinen Code schreiben, wenn nicht klar ist, was der Code tun soll. Wir können keinen Code schreiben, der technische Unmöglichkeiten überwindet. Unseren Code schreiben wir wie Anwälte und Richter — klar, präzise und ohne Kompromisse zuzulassen. Aber das ist nicht immer so.&lt;/p&gt;

&lt;p&gt;Manchmal müssen wir wie Schriftsteller weit ausholen und viel Fantasie zulassen. Dann müssen wir einfach anfangen zu schreiben. Mit Idee aber ohne Plan. Wir beginnen zu schreiben, aber wir kennen das Ende noch nicht. Erst im Laufe des Schreibens merken wir, was wir schreiben wollen. Am Anfang haben wir nur den leeren Bildschirm vor uns, mit einem Anfang aber ohne Ende. In einem Punkt sind wir schlechter dran als der Schriftsteller. Unsere Geschichte wird nie fertig. Sie geht immer weiter und weiter. Und nicht nur das. Nicht mal auf den Anfang können wir uns verlassen. Jederzeit kann der Anfang über den Haufen geworfen werden, ein Mittelteil kommt hinzu oder eine neue Hauptfigur wird eingefügt. Je besser und erfolgreicher unsere Geschichte ist desto schneller passiert das.&lt;/p&gt;

&lt;p&gt;Manchmal müssen wir exakt und präzise sein. Manchmal müssen wir einfach drauflos schreiben, vorpreschen ohne genau zu Wissen wohin. Wir müssen erkennen wann es Zeit ist exakt und präzise zu sein und wann es Zeit ist draufloszuschreiben. Das sagt uns keiner.&lt;/p&gt;

&lt;p&gt;Wir schreiben nie alleine. Immer schreiben wir unsere Geschichte mit anderen zusammen. Mal mit vielen, mal mit wenigen. Wenn wir es gut machen merkt das niemand. Keiner der die Software nutzt soll erkennen wer einen Paragraphen, ein Kapitel oder einen Band geschrieben hat. Dann sind wir erfolgreich.&lt;/p&gt;

&lt;p&gt;Doch schreiben wir anders als der Schriftsteller oder der Jurist. Was wir schreiben sind Anweisungen an die Maschine. Die müssen korrekt sein, sie müssen der Maschine exakte Befehle geben. Die Maschine hat keine Intelligenz, alles was sie tut haben wir für sie aufgeschrieben. Aber noch mehr als das.&lt;/p&gt;

&lt;p&gt;Was wir schreiben muss lesbar sein. Jederzeit müssen andere an jedem Punkt die Geschichte weiterschreiben können. Dazu müssen sie rasch verstehen worum es geht, sie müssen den Plot und die Hauptpersonen erkennen können. Ja sie müssen auch in der Lage sein, die Geschichte in der Art und Weise weiterzuschreiben, wie es andere zuvor getan haben. Nur dann wird es eine Geschichte und nicht viele kurze Geschichten aneinander gereiht.&lt;/p&gt;

&lt;p&gt;Unter keiner unserer Geschichten steht unser Name. Vom Pophit kennt jeder die Band, vom Bestseller den Autor. Uns kennt keiner. Das ist auch gut so. Wir wollen nicht bekannt sein, nicht gefeiert werden. Wenn unsere Arbeit ankommt, unsere Software ihren Dienst gut verrichtet sind wir glücklich. Meistens.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dieser Artikel erschien ursprünglich auf &lt;a href="https://medium.com/@remast/wir-schreiben-code-92bd11c5466d" rel="noopener noreferrer"&gt;medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>german</category>
      <category>motivation</category>
      <category>meta</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
