How I Build Robust, Scalable Go Applications

How I use interfaces to keep my Go applications modular

Dirk Hoekstra
Jan 2 · 3 min read
Build code that stands the test of time — Photo by Cederic X on Unsplash

Suppose we are creating a back-end application in Go. In this back end, we should be able to store and query users.

In this article, I’ll show how I usually set up such a project.


Repositories

In Go, I usually create repositories for resources. A repository is responsible for saving and retrieving a resource. In this case, the resource would be a user object.

I create a userrepo package and create a file, api.go. The API file will hold all the functions that are exported.

This way, there is one central place where you define how other packages can interact with the userrepo package.

I define the UserRepository interface. For now, we only have two simple methods, one for storing a user and one for finding a user.


Implementations

I have defined an interface, now it’s time to implement this interface. Let’s start with a mockUserRepo implementation.

As the name suggests, this won’t do anything but mock all the functions.

I create a file, mock.go, in the userrepo package.

The mockUserRepo implements the UserRepository interface, and for each function, it just prints a message.

Let’s go back to the api.go file and add a New() function. This will return an implementation of the UserRepository interface.


Why Use an Interface?

Since we have defined a UserRepository interface we can have multiple implementations for this.

Way back when I just started with software development, I always scratched my head when looking at interfaces and thought: “So what, I just need one implementation anyway.”

This might be true for small, personal projects, but in larger, real-world applications you usually have multiple implementations.

For example, you could add a cloudUserRepository that connects to a Google Cloud database.

It would make sense to use this in the production environment. However, in your local environment, it would probably be easier to add an SQLite database.

By creating a sqliteUserRepository that implements the UserRepository interface, you can easily accomplish this without having to rewrite a large part of your code.


An Example

OK, I’ll show an example to convince you that interfaces really are awesome.

Let’s create an sqlite.go file in the userrepo package. This file will contain the SQLite implementation of the UserRepository package.

Similarly, let’s create a cloud.go file in the userrepo package that will contain the Google Cloud implementation.

Note that, for now, I just print a debug message, implementing the actual interfaces is out of scope for this article.

Next, I update the api.go file’s New() function.

We pass the environment to the New() function and it will return the correct implementation of the UserRepository based on this environment — Awesome!


Bringing It All Together

Let’s create the main program.

In a new package, main, I create a run.go file.

Here, I use the userRepo.New() function to get the implementation of the UserRepository based on the environment.

If I ever need to swap user repositories on an environment, I only have to change the userrepo.New() function, which is awesome.

Let’s test it by running the following command:

go run main/run.go

Which outputs the following:

cloudUserRepo: mocking the StoreUser func

So, the correct implementation of the UserRepository interface is created.

This is a design pattern that I use a lot and has proven to be very useful. Hopefully, you find the pattern just as awesome as I do!

You can find the repository on GitHub here.

Better Programming

Advice for programmers.

Dirk Hoekstra

Written by

Practical programmer that likes building cool stuff!

Better Programming

Advice for programmers.

More From Medium

More from Better Programming

More from Better Programming

More from Better Programming

More from Better Programming

Why Do Incompetent Managers Get Promoted?

499

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade