How to decouple your Go packages

Decouple your Go packages to increase your Go code maintainability, and make your life easier.

Encapsulation allows us to expose or hide some part of our code to the outside code.

Exposing from packages

We can use packages to expose some part of our code to the outside code by making our declarations start with an uppercase letter.

Example 1:

example.go exposes Hi() to the outside code.

example.go program exposes Hi to the code that doesn’t belong to example package. Outside code can use this as: example.Hi() after importing the example package.

main package calls example package’s `Hi` function.

main package can call example package’s Hi function. Because Hi, is named as Hi, not hi, it starts with an uppercase letter.

Let’s try, Example 2:

Now, example.go doesn’t expose hi function, it “hides” it.
Now, main package can’t call example package’s hi function.

Go will display an error when you try to run the program:

example_main.go:6:2: cannot refer to unexported name example.hi
example_main.go:6:2: undefined: example.hi
This allows us to show or hide some of our implementation of our packages.

Example 3:

Now, let’s try to hide a package’s data but expose a package’s functionality. age data will be hidden, but, Age function will be exposed.

example_2.go exposes Age function but hides age variable.
example_main.go can call example package’s Age function, but it can’t access example package’s age data directly.

→ main package can call example package’s Age function, however, it can’t access example package’s age data, because the name of the age data starts with an lowercase letter.


When you expose it builds your package’s public API. Be careful on what you expose.

So, why do we want to hide access to the data or functionality?

By hiding things, we control access to the functionality and the data inside our packages and we decrease the maintenance cost of our code.

When outside code can access to everything in our code, then when we can’t change something inside our package or that will kill the outside code.

Imagine that we exposed the age data here and it’s being used by a dozen of other outsider code. When we want to get rid of age data, we can’t, because that’ll break the dependent (outsider code) code. It’d be concrete and sticky. It’d kill our code, and, of course, us, slowly. We should decrease the technical debt, not increase it.

Or, in other scenario, if we have exposed the age data, outside code could even change it beyond our control, so our code in the example package would be broken too. Some outside code could change the data inside age, and we wouldn’t be sure about its state, ever. The package will become unstable.

Encapsulation increases the stability of our code.

In Go packages, there isn’t a source-code level local variable that is only belong (visible) to one source code file. Any code in a package shares the same functionalities and data whether they’re exposed or not.

For example: age in the example_2.go, can be accessed by example.go too, because they live inside the same package. Be careful about this when programming with Go.


To learn more about packages, see my other tutorials.

I’m also creating an online course for Go → Join to my newsletter

“ Let’s stay in touch weekly for new tutorials and tips “


My twitter — @inancgumus — I mostly tweet about Go.