Why Go error handling is my favorite

Go has very simple and efficient error handling mechanism. Error as value is very powerful concept and some people find it annoying. I think errors should be annoying so that we don’t ignore them. Most notable aspects of go’s error handling I found myself are: It is just straight forward and simple, I didn’t have to do anything clever to tweak it and make it more erganomic. I got used to it quickly after a bit of skepticism. I believe It’s common for us to force a familiar paradigm when we try new languages and when it’s different, we tend to question it. I had to think more about error handling and it made me write more robust code. I always write prototypes in other languges by ignoring errors and it can slip to production, even if I ignore errors in go, there is an explicit _ which reminds me that I’m ignoring an error. Error as value In go, a typical function defintion can give away if it returns an error or not. If a function returns an error, it’s usually the last return value. This makes it very easy to identify if a function can return an error or not. ...

Implementing Redis in Golang

Redis is well known for a in-memory data store which is widely used as cache, database and message broker. In this article, we will implement a simple Redis client in Golang. Let’s look at the basic parts like, Listening to a port Accepting connections Reading the commands Parsing the commands Handling the commands Listening to a port We can use the net package in Golang to listen to a port. We can use the net.Listen function to listen to a port. ...

Connecting to Consul & Vault using Golang

Consul is a tool for service discovery and configuration. It provides a way to discover services and manage configurations in a distributed system. Vault is a service that help us to manage secrets and protect sensitive data. It provides a secure way to store and access secrets like API keys, passwords, certificates, etc. Both are similar tools provided by HashiCorp Where we can access the services using the HTTP API. ...

Golang Thread Blocking Entities

Golang has good concurrency support using goroutines. Goroutines are lightweight threads managed by the Go runtime. Goroutines are multiplexed to fewer OS threads. Goroutines are non-blocking, and they are not scheduled by the OS. The Go runtime schedules the goroutines. The scheduler uses a technique called M:N scheduling. M goroutines are multiplexed to N OS threads. The scheduler schedules the goroutines to the OS threads. The scheduler uses a technique called work-stealing to schedule the goroutines ...

Using Pkl in Go

Pkl is a config managment language developed by Apple. It is a simple language to manage configuration files. It has plugin support for popular editors and support for golang. Sample project Let’s start with a simple go project. go mod init pkl-sample touch main.go package main import ( "fmt" ) func main() { fmt.Println("Hello, World!") } Install pkl First, let’s install pkl using brew. brew install pkl Then, Let’s install pkl-go library in our project. ...

Swagger Docs in Go

Golang is a very good language to create web api servers. I like gofiber framework for creating web api servers. In this article, we will see how to use Swagger in Go especially with gofiber framework. Install swaggo/swag go install github.com/swaggo/swag/cmd/swag@latest Create a new project go mod init github.com/username/projectname Setup Gofiber and Swagger In the code below, we have created a simple API using gofiber framework. The annotations are used to generate the swagger documentation. ...

Go has less features, so I'm more productive

Golang is well known for the simplicity and performance it offers. It follows a procedural programming paradigm and has a very minimalistic syntax. Sometimes, it’s too verbose compared to some enterprise languages like Java, C# and Python. But, it’s the same reason why I’m more productive with Go. Limited but essential features Go allows us to achieve something in one or only limited amount of ways. This itself is a huge productivity booster as there will be limited choices of patterns to choose from, which makes it easier to make decisions. It’s like choosing a flavor of ice cream from a list of 10 flavors vs a list of 100 flavors. It’s easier to choose from 10 flavors than 100. ...

Go - Testing

Unit tests in Go can be written using testing package. We require to create a file with _test.go suffix to write tests for a package. Conventionally, the test file should be in the same package as the code being tested. The test file should import the testing package and the package being tested. eg: . ├── main.go └── main_test.go Writing Tests Suppose we have a function Add in main.go which adds two numbers. ...

Go - Factory Pattern

In golang, we use interfaces to define a contract for a particular type. Factory pattern uses this interface to create instance / object of a particular type like Storage, Service, Document etc. Implementing Factory pattern Define an interface with a method to create the object. package factory type Document interface { Render() string } Create different types which implement the interface. package factory type PDF struct { data string } func (p *PDF) Render() string { return "PDF: " + p.data } type Word struct { data string } func (w *Word) Render() string { return "Word: " + w.data } Create a factory function which returns the object based on some condition. package factory func NewDocument(docType string, data string) Document { switch docType { case "pdf": return &PDF{data: data} case "word": return &Word{data: data} default: return nil } } Example usage func main() { pdfDoc := DocumentFactory("pdf") wordDoc := DocumentFactory("word") pdfDoc.Render() wordDoc.Render() } This pattern is useful when we have different implementations of similar Interfaces like postgres storage, redis storage etc.. and It also helps to switch between these implementation if they’re interchangable. ...

Go - Builder Pattern

Builder is a common pattern to create or initialize a particular object. It helps to break down individual steps of the creation by providing functions we can use to set different properties and then usually with a Build method, which uses these properties to create the object. Implementing Builder pattern Define a struct with all the properties of the object. package builder type User struct { UID string Name string Email string Password string } Create methods to set the properties of the object. // creates a new UID for the user func (u *User) createUid() *User { u.UID = generateUID() return u } // sets the name and email of the user func (u *User) setNameEmail(name, email string) *User { u.Name = name u.Email = email return u } // sets the password of the user func (u *User) setPassword(password string) *User { u.Password = hashPassword(password) return u } Create a Build method to create the object. // Build creates a new user func (u *User) Build() *User { return u } Example usage package main import ( "builder-pattern/builder" "fmt" ) func main() { user := &builder.User{} user.createUid().setNameEmail("Adharsh", "dev@adharsh.in").setPassword("password").Build() fmt.Println(user) } The key is to make the methods return the pointer to the object so that we can chain the methods together. This is a common pattern in Go and is used in many places. ...