Packages and Modules
Go modules, package organization, and dependency management vs Maven
Introduction
In this lesson, you'll learn about packages and modules in Go. Coming from Java, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In Java, you're familiar with go modules, package organization, and dependency management vs maven.
Go has its own approach to go modules, package organization, and dependency management vs maven, which we'll explore step by step.
The Go Way
Let's see how Go handles this concept. Here's a typical example:
// go.mod — like pom.xml
// module github.com/user/myapp
// go 1.21
// require (
// github.com/gin-gonic/gin v1.9.1
// )
// Package declaration (every .go file)
package math // package name = directory name (convention)
// Export: uppercase = public, lowercase = package-private
func Add(a, b int) int { return a + b } // exported (public)
func helper() int { return 0 } // unexported (package-private)
const PI = 3.14159 // exported
// Import
package main
import (
"fmt" // stdlib
"math/rand" // stdlib subpackage
mymath "github.com/user/myapp/math" // local package
"github.com/gin-gonic/gin" // external
)
func main() {
fmt.Println(mymath.Add(1, 2))
fmt.Println(rand.Intn(10))
}
// Commands
// go mod init github.com/user/myapp // like mvn archetype:generate
// go get github.com/gin-gonic/gin // like mvn dependency:resolve
// go build ./... // like mvn compile
// go test ./... // like mvn test
// go build -o app . // produces single binary (unlike JAR)Comparing to Java
Here's how you might have written similar code in Java:
// Java package = directory path
package com.example.math;
// Import
import java.util.List;
import static java.lang.Math.PI;
import com.example.util.StringUtils;
// Access control keywords
public class Calculator {
public int add(int a, int b) { return a + b; } // accessible everywhere
protected int sub(int a, int b) { return a - b; } // subclasses
int mul(int a, int b) { return a * b; } // package-private
private int div(int a, int b) { return a / b; } // this class only
}
// Maven coordinates: groupId:artifactId:version
// com.google.guava:guava:32.1.3-jre
// mvnrepository.com to find libraries
// Build: mvn compile
// Test: mvn test
// Package: mvn package → produces target/app.jarYou may be used to different syntax or behavior.
Uppercase = exported (public); lowercase = unexported — no access modifier keywords
You may be used to different syntax or behavior.
go.mod declares module path and dependencies; go.sum is the lockfile (like pom.xml + lock)
You may be used to different syntax or behavior.
Go builds to a single binary — no JVM/JRE required on deployment machine
You may be used to different syntax or behavior.
import path = module path + directory path (e.g. github.com/user/app/math)
You may be used to different syntax or behavior.
go get = mvn dependency:get; go mod tidy removes unused deps
Step-by-Step Breakdown
1. Export by Capitalization
No public/protected/private keywords. Uppercase = visible outside the package; lowercase = package-private only.
public class Calc {
public int add(int a, int b) { return a+b; }
private int helper() { return 0; }
}// In calc.go:
package calc
func Add(a, b int) int { return a+b } // exported
func helper() int { return 0 } // unexported2. go.mod and Dependencies
go.mod is the module manifest. 'go get' downloads and pins dependencies. 'go mod tidy' removes unused ones.
<!-- pom.xml -->
<dependency><groupId>com.google.guava</groupId>...</dependency>// go.mod
module github.com/user/app
go 1.21
require github.com/gin-gonic/gin v1.9.1
// Commands
go get github.com/gin-gonic/gin@latest
go mod tidy // remove unused3. Single Binary Output
go build produces a self-contained binary. No JVM needed on the deployment machine — just copy the binary.
mvn package // produces JAR (needs JRE to run)
java -jar target/app.jargo build -o app . // produces single binary
./app // runs directly, no runtime needed
// Cross-compile for Linux from Windows:
GOOS=linux GOARCH=amd64 go build -o app-linux .4. init() Functions
Packages can declare init() functions that run automatically at startup — like static initializer blocks in Java.
static {
// Java static initializer
System.setProperty("key", "value");
}package db
var pool *sql.DB
func init() {
var err error
pool, err = sql.Open("postgres", os.Getenv("DSN"))
if err != nil { panic(err) }
}Common Mistakes
When coming from Java, developers often make these mistakes:
- Uppercase = exported (public); lowercase = unexported — no access modifier keywords
- go.mod declares module path and dependencies; go.sum is the lockfile (like pom.xml + lock)
- Go builds to a single binary — no JVM/JRE required on deployment machine
Key Takeaways
- Uppercase = exported; lowercase = unexported — no access modifier keywords
- go.mod: module path + dependencies; go.sum: lockfile; go mod tidy: cleanup
- go build produces a single static binary — no JVM/JRE needed on deployment
- init() functions auto-run before main(); each package can have multiple