Golang Project Structuring: A Guide for Backend Developers to Boost Productivity

Photo by Lala Azizli on Unsplash

Golang Project Structuring: A Guide for Backend Developers to Boost Productivity

Every newbie developer comes up with the problem of how to properly organize their project’s architecture and structure. After all, organizing project code is a constantly evolving problem, whereas following a standard structure keeps the code clean and improves team productivity.

My name is Wisdom, and I work as a backend developer at inDrive. When I started coding in Go, I used to spend a lot of time looking for project structuring standards. Long story short, I ended up finding no official standard with accurate specifications: the information was either incomplete or it wasn’t what was needed. This inspired my decision to write my own guide based on my hands-on experience. This guide is designed for novice developers and it focuses on how to structure a project in Golang.

Why I decided to write this article

If properly organized at the outset, project architecture and structure will facilitate the development and scaling, while also making it easy to introduce new developers to the project. A flat structure is also an option for small projects with one main file, but it is not practical for larger projects.

I have worked on quite a few projects in my career, and I’ve taken away something from each one of them for future reference and use. I recommend you look into this project, as many people use it as a guide when setting up a structure. My example will use a more compact structure as we will be exploring the /internal directory in detail.

Note that I’m not claiming this methodology is the best fit or the only option for handling this situation. I think it’s a good place to start, though. Let’s look at the structure of the project root:

The root structure of the application

Directories

/cmd

The entry point for our application. The directory name for each application has to match the name of the executable you want to build. Make sure you don’t put too much code into this directory. The most common practice is to use a small main function that imports and calls all the necessary code from the /internal and /pkg directories.

Structure of the /cmd directory

/internal

The heart of our application, i.e., all its internal logic, is stored here. /internal is not imported into other applications and libraries. The code written here is intended solely for internal use within the code base. Starting from the Go 1.4 version, a defined mechanism has been in place that prevents the importing of packages outside of this project if they are inside /internal.

/internal is where we store the business logic of the project, together with all work related to databases. In other words, all the logic is associated with this app. The structure is inside /internal and can be organized in a variety of ways, depending on the specific architecture used. I’m not going to go into this in too much depth right now, but I will illustrate in broad strokes what it looks like. Here is an example of a three-layer architecture, where the app is divided into three layers:

  1. Transport.

  2. Business.

  3. Databases.

The logic should be such that the layers hierarchically communicate with each other from top to bottom, and vice versa. No layer may “skip” over its intermediate peer (e.g. when the transport layer communicates directly with the database) and no layer that is below another one may communicate directly with the layer above (e.g. when the database communicates with the transport layer).

A three-tiered architecture model

The transport layer:

The network layer of the application, where the end-user interacts with the app. Once the request has been processed, all the information collected goes to the layer below.

The business layer:

As the name implies, this layer contains the business logic that supports the app’s core functions. If the logic involves databases, we move down to the layer below.

The database layer:

This layer is responsible for interacting with permanent vaults, such as databases, and other non-business-related information processing. For instance, reading and writing in the database.

/internal directories:

  • /app
    The point where all our dependencies and logic are collected and run the app. The run method is called from /cmd.

  • /config
    Initialization of the general app configurations that we wrote at the root of the project.

  • /database (the database layer)
    The files contain methods for interacting with databases.

  • /models (the database layer)
    The structures of database tables.

  • /services *(the business layer)
    *The entire business logic of the application.

  • */transport (the transport layer)
    *Here we store HTTP server settings, handlers, ports, etc.

Structure of the /internal directory

/pkg

In /internal we store code that we were unable to import into other applications, whereas in /pkg we store libraries used in third-party applications. This makes it possible to import them into a different project and avoid the need to duplicate code from project to project. Generally speaking, it is our custom or shared libraries that are stored here.

You don’t have to use this directory if the project is very small and it makes no practical sense to add a new nesting level.

/configs

Static configurations of our app related to the process of building the application. Normally, these are YAML files.

/API

Documentation for your API. OpenAPI or Swagger specifications, JSON Schema files, protocol definition files.

/build

Configuration files for the project build, Docker container, etc.

/deployments

Contains files related to deployment: Ansible playbooks, Docker Compose manifests, Kubernetes manifests and settings, and Helm diagrams.

/docs

Documenting code is an essential element of a project’s initial phase. We, therefore, store all code and design documentation (in addition to GoDoc automatic documentation) here.

README.md

It’s hard to imagine that anyone would want to perform a deep dive into your code if they haven’t been provided with a general description of the project. For this reason, the README file is also required.

Common directories

I’d like to point out some common directories that I haven’t included in my project. You can check them out and, if necessary, keep them for future reference and use.

/scripts

Scripts for building, installing, analyzing, and conducting other operations on the project. They make it possible to keep the main Makefile small and simple.

/test data

Additional external applications and data for testing. You can organize the structure of the /test directory any way you want it. For large projects, it makes sense to create a nested directory with data for tests.

/tools

Project support tools. Note that these tools can import code from the /pkg and /internal directories.

/assets

Other resources needed for this kind of work: pictures and logos, for example.

/web

This directory will be needed if you are implementing a web application. Here you can find specific components for web applications: static web resources, server-side templates, and single-page applications.

/migrations

This contains all migrations related to databases, e.g. SQL files.

Conclusion

Needless to say, the structure I have suggested here is not set in stone and you don’t have to follow it to a T. You can take a part of it and edit it to suit your own needs and liking. When I was starting out, though, no detailed guide like this was available to help me along the way. So, I hope this article was helpful to you!

Just in case, I will leave the link to this public sample project on GitHub here. Feel free to ask any questions you may have in the comments section