How to properly kickstart your first Golang project

Mateusz Gajewski - Tuttle
Jit Team
Published in
7 min readJun 29, 2021

Starting out and learning a new technology is always a challenge. It’s sort of like trying to find a treasure — tutorials are your map and the goal is to gain a new skillset. For older, mature languages it is quite easy — all the maps usually point to one, maybe two things to focus on. For Java web development it’s fairly easy to decide to learn Spring + JPA. For JavaScript frontend technologies, you will probably want to start with Angular or React as your goal.

The challenge becomes a little more complicated when you want to start your journey with a fairly immature technology where there are multiple “best” solutions to achieve your goals. It’s like wanting to find the treasure using multiple maps with different treasures marked on them. You know you want to find one of them, but it’s hard to decide which way to go because all are marked as the best or at least awesome. This is, in my opinion, the case with Go — Google’s programming language. Just look at Awesome Go (https://github.com/avelino/awesome-go) — a list of tools to use in Go. Every section is very long and filled with “fast”, “simple” or “great” tools and it seems there is no one clear winner.

In this article, I will show you the criteria I used to pick Go-based technologies for our Go template for in-house Jit Team use. I will try to propose a structure of the application and show you an actual sample of a simple email sending service. Keep this in mind: it is the first article in a series that will later show the evolution of this service. For now, I will be concentrating on getting an HTTP server up and running, connecting it to a database and email server and creating a simple DI implementation (with repository-service-controller architecture). In the next parts of the series I will be adding ORM, database migrations, authentication, configs, and more — be sure to follow us and stay up to date!

Tools

To build a simple service that sends emails I will need some frameworks/libraries/tools for:

  • Handling HTTP requests
  • Database connection
  • Sending emails

The criteria that I chose to pick the tools for our Go stack are mainly simplicity in use and size of the community. I want something that can quickly kickstart the creation of features in or projects. On the other hand, I don’t want to get left with a library that seems nice at the time of adding it to or project but will be abandoned without any support or maintenance.

Having this in mind, here are the tools that I chose.

1. Handling HTTP requests — one of the cool things about Go is that is has a built in http package and I can use it perfectly fine by adding some external tools to simplify our work. I chose the Gorilla toolkit which has a lot of cool features, examples and a community that surrounds it. In this article I will be using the Gorilla MUX package for routing requests.

Alternative might include:

  • Gin — a web framework including many features that are available in the Gorilla packages (and quite possibly even more) which seems to have a lot of community support
  • Iris — another framework that is advertised as fast and easy to use with a community around it

2. Database connection — a quite simple driver with a lot of community support is Pgx, it also has a connection pool library in its family which will come in handy later.

3. Sending emails — simple and straightforward GoMail library.

Implementation

First of all, the source code can be found here: https://github.com/gajewa/go-email-service

I will go by different parts of the code in small steps.

1. Project structure.
I am a big fan of the repository-service-controller architecture and dividing the code into packages with these three layers. Some people say that one of the flaws of this is that it is too general — a lot of code gets put into one place and it is hard to look for classes/files.

I’d say it’s exactly the opposite. If you start dividing your project into small pieces (like domain packages each of which will contain a controller, business layer and DAO layer) you will probably quite quickly find cases of files/classes that are needed in different packages. So then, you start wondering where the file should be put — in one of the domains or in some shared package? And then should the shared package be globally shared or only in certain domain packages?

This usually makes progress on a project a lot slower in early phases of the project and can become quite confusing. And often, it will end up in a lot of little intertwined packages each of which have a very small amount of files in them. If you make the packages separate dependencies it will be a dependency hell.

2. Dependency injection
For me, coming from a Java/Spring background, the Go syntax was quite bizarre at the beginning. You don’t have your typical classes with declared fields and methods and then objects based on them. You have structs containing fields on which you can declare methods outside the struct definition itself. You can see this in the EmailController:

First you have the struct definition which tells us what fields the struct will have. Then a little lower there is a function that looks like it takes in arguments in two different pairs of brackets. This is a declaration of a function that will act for the struct like a method for a Java class.

As you can see, there are also “normal” functions without the first pair of brackets. Here is an example of a function that creates a new instance of the EmailController using the new(struct) keyword:

These functions will not be available on the EmailController struct instance, they are only available when importing the controller package. This is also one of the quirks of Go — even though you can write multiple files in one package they are all available inside the package as if it was one file. And on the other hand the whole package is imported into other files, not only certain files. You can see this in the server.go file where the controller and repository packages are imported and used to build the dependency injection structure.

As you can see, first I use the NewRouter() function to get an instance of the Gorilla MUX router. Then, I do the same using the NewEmailRepository and NewEmailController functions that I wrote on my own giving all the needed arguments to start each instance of a struct (database connection instance for the Repository and repository instance for the Controller). The New* methods are not part of any struct — they are somewhat static methods available after importing the package.

One last additional note here about the routing. I wanted everything that had to do with the router inside the controller itself to be in the controller file. Golang does not have annotations by which I can register routes like in Spring, you have to do it manually like in the Register function of the EmailController:

I didn’t want to have to look in some central file to see which method is invoked in each route, so I created a Register function that is invoked when the controller instance is created. This way, I only need to remember about adding this once in the main package level, the routes are where the code they execute is and they are separated in groups.

3. Data access layer
For now the data access layer is as simple as possible using the pgx driver. In the future I will add an ORM and connection pool support. In the server.go file, you already saw registering of the database connection which is injected into the repository. After that, the code is pretty straightforward, I create a query and then go through the rows that come back from the database and collect and return them.

The panic exception raising might not exactly fill you up with confidence while writing the code, but I guess that’s just something we will have to live with 😄.

For this to make sense, I also need to populate the database sometimes. So each mail that is sent is also persisted to the database. To do this, I need to create a Save() function in our Repository:

Summary

And there we have it, a simple REST service that sends emails and reads from the database. My proposal of the project structure, some tools to use and what in my opinion was the trickiest to comprehend — how to setup the whole dependency injection mechanism. Stay tuned for next the parts coming soon (following Jit Team and me is always a good idea) and feel free to give any feedback or suggestions in the comments.

--

--