Work with Packages in Golang

Stay DRY with Go packages!

Jonathan Seow
7 min readApr 10, 2021
Photo by Brandable Box on Unsplash

One of the most fundamental design principles in writing software is the DRY principle — Don’t Repeat Yourself. As software engineers, we should always avoid writing the same code again and again.

DRY teaches us to design our software such that it is built upon reusable and modular units of code. This helps us save time and reduce software maintenance costs in the long run.

In most programming languages, functions are the most basic unit of reusable code. However, as our software grows in size, it is good practice to group functions into separate logical units. In Go, this can be done easily through packages.

The adorable Go gopher

In this article, I will explain how you can work with Go packages. You will learn how to import a package, export from a package, set up your own Go package, and install third-party packages.

I assume you have some programming experience and you are familiar with the basic syntax of Go.

Let’s get started! 🏃

What is a Go package?

A Go package is a directory in your project workspace that houses one or more Go source files or other nested Go packages.

In Go, every source file must belong to a package. All Go source files must begin with a package declaration like below.

package <package_name>

Every function, type, and variable of a source file belongs to its declared package and can be accessed by other source files within the same package.

Go source files that live in the same directory must belong to the same package. Although it is not necessary to name a package after its directory, it is a good convention that you should follow.

A simple example

Go comes with a handful set of built-in packages. One of them is the fmt package that provides versatile I/O functionalities. To use this package, we can import it as follows:

import "fmt"

When you import a package, you have access to the functions exported by the package. You can use these functions using the dot operator. One of such functions exported by fmt is Println() which formats and writes data to the standard output.

Using the fmt package

The eagle-eyed readers may have noticed a benefit of this design pattern. Accessing an exported function via the dot operator helps to prevent naming conflicts. You can reuse function names across different packages, which helps to keep function names concise and meaningful!

Package main

In Go, there are two types of packages: an executable package and a utility package.

An executable package, as the name suggests, is a special package that holds an executable program for Go to compile and run.

On the other hand, a utility package contains reusable helpers that support the program in an executable package. The fmt package of Go is an example of a utility package.

To create an executable package in Go, you need to meet two criteria:

  1. The name of the package must be main .
  2. It must contain a function called main() , which serves as the entry point of the executable program.

Let’s look at an example of a simple source file main.go in the main package.

The main() function

To execute a main package, you can either use go build to compile and then run the executable file manually, or use go run to do it in one step.

$ go run main.go

In the example above, there is only one source file in the main package. With more complex programs, there could be more than one source file in a main package. To compile and run them, you need to point Go to the directory of the main package.

$ go run /path/to/directory/of/main_package

Multiple and nested imports

In most cases, you would want to import multiple packages. There are two ways where you can do this in Go:

Using multiple import statements
Using one import statement

Personally, I prefer the second method because it looks much cleaner without the repeated import keywords!

Sometimes, packages are designed to be the children of a parent package. This parent-child relation is logical in cases where the child package performs a specific task of the parent package.

For example, inside Go’s math package, there is a nested rand package that implements pseudo-random number generators. We can import the rand package and use it as follows:

Using the rand package

In Go’s lingo, the last element of an import path indicates the nested package that is imported into a source file.

Export from packages

If you come from the world of JavaScript, you should be familiar with the export keyword when working with JavaScript modules.

In Go, we can export functionalities from packages as well. However, instead of using a designated keyword like JavaScript, Go relies on letter casing!

Any functions, types, or variables with a capitalized name are exported and visible outside of a package.

On the other hand, anything that does not start with a capital letter is private, i.e. not accessible outside of the package.

Export Greet() and not sayHello()

Restricting the export of certain functionalities from a package is a good design practice. It enables you to “force” other developers to use your package through specific interfaces. This minimizes the misuse of a package and unintended errors.

Create Go packages

Enough of theory! Let’s try to create our own Go packages and use them with the concepts you have learned.

Open up your terminal and type in the command below to create a project directory. I’ll name it pkg-tutorial . You can name it whatever you want.

$ mkdir pkg-tutorial

Then, we need to create a Go module. Module is Go’s new dependency management system introduced in version 1.11.

In simple words, a Go module is a collection of Go packages managed by a go.mod file. Every Go module must have a path defined in go.mod .

The path in go.mod represents the path to the module, and it is also used as the import path for the packages in the module.

Do not panic if you do not understand what I just said. Go modules deserve a separate article. For now, you just need to type the following commands in your terminal.

$ cd pkg-tutorial
$ go mod init github.com/jseow5177/pkg-tutorial

github.com/jseow5177/pkg-tutorial is the module path. After you run the commands above, you should see a go.mod file created in your workspace.

Next, we will create three utility packages: numbers, texts, and greets with greets nested in texts. The entry point of our program is in main.go which belongs to the main package at the root of our workspace.

After adding a couple of source files, the project structure will look like this:

Project structure

math.go

Two simple functions: Sum() and Subtract()

casing.go

Two simple functions: TitleCase() and lowerCase()

welcome.go

A simple constant: Welcome

main.go

The main() function

Once you are done, at the root of your project workspace, execute go run main.go in your terminal. You should see the following output:

I love Go!
2 + 5 is 7
2 - 5 is -3
Hello World

Here are a few things that you should take note of:

  1. All import path of packages is relative to the module path github.com/jseow5177/pkg-tutorial .
  2. Nested packages are created as subdirectories. You import them as usual starting from the module path.
  3. fmt is Go’s built-in package. Hence, you won’t be importing it from our module.
  4. The lowerCase function in casing.go is not exported. Try calling it in main.go and see what you get!
  5. I followed the convention where a package name is the same as the directory name. However, this is not needed for the main package.

Pretty simple right?

Install third-party packages

Go’s built-in packages provide a wide range of functionalities, but they may not be sufficient for your project.

In most cases, you would require packages written by other developers in the open-source community. Fortunately, Go has made it easy for you to install third-party packages into your project.

For example, gorilla/csrf is a Go package that protects your application against cross-site request forgery (CSRF) attacks.

To install it, you use the go get command and provide that path to the gorilla/csrf package.

go get github.com/gorilla/csrf

If you haven’t noticed, the module path above is the link to the package’s GitHub repository!

After you run the command, Go will fetch the package from GitHub into your local project. The go.mod file will be updated accordingly to make gorilla/csrf a project dependency. You can then import it as follows:

import "github.com/gorilla/csrf"

Final Thoughts

That is all for packages with Go! In this article, you have learned about Go packages and how you can use them to organize your code in a Go project.

As the size of a project grows, Go packages can keep our code organized, modular, and reusable. Always remember to stay DRY.

Thank you for reading. Peace! ✌️

--

--