# Go Programming Language — Packages

2020-01-24 — Nailcan Küçük
Tags: go, programming

How Go organizes code with packages: naming conventions, exported vs unexported identifiers, package organization strategies, circular imports, and managing external dependencies.

Canonical: https://www.nailcankucuk.com/blog/go-paketler/

---

## Go Programming Language — Packages

![Go Programming Language](/images/blog/go-cover.png)

In Go, code organization is achieved through packages. A package represents the files inside a directory on disk. Both the libraries you use within your code and your application's main entry point are packages.

#### Naming

Package names are expected — but not required — to match the name of the directory containing them.

A package declaration goes at the top of every source file using the `package` keyword. Every source file must have a package declaration:

```go
package sendMail

import {
  ...
}
```

If a package is located at:

```go
$GOPATH/src/foo/bar
```

You import it like this:

```go
import "foo/bar"
```

To import a package hosted on GitHub under a repository named **foo**:

```go
import "github.com/nailcankucuk/foo/bar"
```

When using an imported package, you typically access its functions through the last path element:

```go
package main

import "github.com/nailcankucuk/foo/bar"

func main() {
  bar.sayHello()
}
```

#### Executable Packages

An executable program must have a source file declaring `package main` and containing a `main()` function. The `main()` function is defined exactly once, takes no parameters, and has no return type. It is the program's entry point:

```go
package main

func main() {
  fmt.Println("Hello!")
}
```

#### Scope and Visibility

Go has no `public`, `private`, or `protected` keywords. Instead, visibility is determined by the **case of the first letter** of an identifier:

- An uppercase first letter means the identifier is **exported** (accessible from other packages).
- A lowercase first letter means the identifier is **unexported** (package-private).

```go
// Accessible from other packages
func Foo() {}

// Only accessible within this package
var bar string
```

You cannot directly access or assign unexported fields of a struct defined in another package:

```go
package main

import (
  "fmt"
  "github.com/nailcankucuk/userops"
)

func main() {
  user := userops.NewUser("Nail", "Küçük", "12345")
  fmt.Printf("%+v\n", user)
  // Expected output: {First:Nail Last:Küçük password:12345}

  // Direct access to unexported field is not allowed:
  fmt.Println(user.password)
  // ./main.go:17:18: user.password undefined (cannot refer to unexported field or method password)

  //user.password = "new"
  // ./main.go:18:6: user.password undefined (cannot refer to unexported field or method password)
}
```

As a best practice, avoid using unexported types as the return type of an exported function. The code will compile, but it is semantically incorrect:

```go
type bar struct {}

func Foo() bar {
  return bar{}
}
```

#### Package Organization

When starting to write code, it is not always obvious how to structure your packages. Many approaches exist, but none is universally best. Often the relationships and design patterns only become clear as the codebase matures — so one valid strategy is to write the code first and refactor into packages once it reaches a certain level of maturity.

One critical constraint to keep in mind: **Go does not allow circular package imports.**

- If package A imports package B, then package B must not import package A.
- If A imports B, B imports C, and C imports A, this also forms a cycle.

Organizing packages strictly by domain module can easily lead to circular references. For example, separating `users` and `department` into their own packages may eventually require each to import the other, creating a cycle.

A recommended approach is to organize packages into four categories:

- Domain Package
- Implementation Packages
- Mock Package
- Binary Packages

#### Domain Package

The domain package contains the application-specific types at the core of the project. It may include:

- Data models (structs): `Account`, `User`
- Service interfaces: `AccountService`, `UserService`
- Utility functions: `SortUsers()`, `UserCache`

#### Implementation Packages

Implementation packages are named after the technologies they use, and contain the concrete implementations of domain interfaces.

For example, CRUD operations on a `Foo` struct using PostgreSQL would live in a `postgres` package, while Redis-backed caching for the same struct would live in a `redis` package. This isolates implementations by technology and enables independent testing:

```go
demo/
└── foo.go
└── postgres
│   └── foo.go
└── redis
    └── foo.go
```

#### Mock Package

Test doubles (mocks) for all services are collected in a single `mock` package:

```go
demo/
└── mock
    └── foo.go
```

#### Binary Packages

The compiled binaries for each executable in the project live under a `cmd` directory, with each binary in its own subdirectory:

```go
demo/
└── cmd
    ├── demoserver
    │   └── main.go
    └── democlient
        └── main.go
```

A complete example project structure:

```go
demo/
├── cmd
│   ├── demoserver
│   │   └── main.go
│   └── democlient
│       └── main.go
├── mock
│   └── foo.go
├── postgres
│   └── foo.go
├── redis
│   └── foo.go
└── foo.go
```

For large projects that span multiple domains, split the code into separate packages per domain. Common types and interfaces shared across domains can live at the root level. The benefits:

- Enforces clean communication between layers through interfaces.
- Each package can be tested independently.
- Prevents circular dependencies.
- Keeps the codebase maintainable as it grows — issues stay contained within their package.

#### Installing and Updating External Packages

Like most languages, Go allows you to use packages written by others. To install an external package, use the `go get` command. Packages are downloaded into the directory defined by the `GOPATH` environment variable:

```go
$ go env GOPATH
/Users/nailcankucuk/go
```

To download a package:

```go
$ go get github.com/nailcankucuk/foo
```

This places the package at:

```go
$GOPATH/src/github.com/nailcankucuk/foo
```

You can then import and use it in your code.

To update a package to its latest version (or download it if it doesn't exist locally):

```go
$ go get -u github.com/nailcankucuk/foo
```
