Category Golang

Golang Tips & Tricks #5 - blank identifier in structs
1 min read

While working with structures, there’s a possibility to initialize the structure without providing the keys of fields.

type SomeSturct struct {
  FirstField string
  SecondField bool
}

// ...

myStruct := SomeSturct{"", false}

If we want to force other (or even ourselfs) to explicitly providing the keys, we can add _ struct{} in the end of the structure.

type SomeSturct struct {
  FirstField string
  SecondField bool
  _ struct{}
}

// COMPILATION ERROR
myStruct := SomeSturct{"", false}

The code above will produce too few values in SomeSturct literal error. Try it yourself.

Golang Tips & Tricks #4 - internal folders
1 min read

While developing a library, we create a directory structure to keep the code organized. However, some exported functions or struct should not be used by users of the library. The achieve that, call the package internal.

.
├── bar
│   ├── bar.go
│   └── internal
│       └── foobar.go
├── internal
│   └── foo.go
└── main.go

In the example above, the foo.go can be included only in the main.go. What’s more, only the bar.go is able to include the foobar.go file. It means, that only the direct parent of the internal package is allowed to use it’s internals.

Golang Tips & Tricks #3 - graceful shutdown
2 min read

In the microservices’ world, one thing what’s worth considering is a graceful shutdown. This is important to not lose data while shutting down a container. The container orchestrator like Kubernetes can restart the container by sending SIGTERM or SIGINT signal. Those signals can be handled to safely close all connections and finish background tasks.

Signals are propagated using os.Signal channel. You can add the above code to your main.

var gracefulStop = make(chan os.Signal)
signal.Notify(gracefulStop, syscall.SIGTERM)
signal.Notify(gracefulStop, syscall.SIGINT)

Then, we need a goroutine to handle signals.

Golang Tips & Tricks #2 - interfaces
1 min read

When it comes to interfaces, a good practice is to create an interface where you’ll use it. Creating interfaces in advanced is not recommended in Go. There are two exceptions:

  • you’re creating a library which will be used in different projects
  • you’ll have more than 1 implementation

In the example below, we have a storage implementation.

type inMemoryStorage struct {
   mutex *sync.Mutex
   storage map[string]*Value
}

func NewStorage() *inMemoryStorage {
   return &inMemoryStorage{
      storage: map[string]*Value{},
      mutex: &sync.Mutex{},
   }
}

func (s inMemoryStorage) Set(ctx context.Context, value *Value) error  {
   s.mutex.Lock()
   s.storage[value.key] = value
   s.mutex.Unlock()
   return nil
}

func (s inMemoryStorage) Get(ctx context.Context, key string)  (*Value, error)  {
   if val, ok := s.storage[key]; ok {
      return val, nil
   }

   return nil, nil
}

func (s inMemoryStorage) GetAll(ctx context.Context)  map[string]*Value  {
   return s.storage
}

func (s inMemoryStorage) Remove(ctx context.Context, key string) error  {
   s.mutex.Lock()
   delete(s.storage, key)
   s.mutex.Unlock()
   return nil
}

As you can see, we skipped the interface(s) because they are not needed here.

Golang Tips & Tricks #1 - errors
1 min read

You should use the package github.com/pkg/errors instead of errors package for errors in your applications. The default package lacks a few things like:

  • stack trace
  • easy appending message to the error
  • and more

It helps with debugging a lot. Below you can find an example error message with the stack trace.

An important thing to remember is that you should wrap every error which is from any external library or your freshly created error you want to return.

Go deeper – Database connection pool
3 min read

Golang uses a connection pool to manage opened connections for us. As a result, new connections are used when no free connection left and reuses them when golang finds an idle connection. The most important thing is that when two queries are called one by one it does not mean that the queries will use the same connection. It may be true if not in every case.

In the example below, you can find two queries which may seem to be executed in one connection. The problem is that the first query may use a different connection than the second one.

Be aware of copying in Go
3 min read

Some bugs are very hard to find and to reproduce but easy to fix. To avoid them, it’s helpful to know how the tools we’re using work under the hood. From this article, you’ll learn what shallow and deep copy are and which errors you can avoid thank’s the knowledge about them.

Can you find a problem with the code below?

	q1 := NewQuestion(1, "How to be cool?")
	q1 = q1.AddAnswer(1, "eat peanuts")

	q2 := q1

	q2 = q2.AddAnswer(2, "visit developer20.com regulary!")
	fmt.Println("How to be cool?")
	q1.ShowAnswers()

It’s hard to say what’s wrong because, at first glance, the code seems to work OK. When we run the code we receive the output:

How to send multiple variables via channel in golang?
1 min read

Channels in golang are referenced type. It means that they are references to a place in the memory. The information can be used to achieve the goal.

Firstly, let’s consider using structs as the information carrier. This is the most intuitive choice for the purpose. Below you can find an example of a struct which will be used today.

type FuncResult struct {
	Err error
	Result int
}

func NewFuncResult(result int) FuncResult {
	return FuncResult{Result: result}
}

The idea is to create a channel from the struct, pass the channel to a function and wait for the result.