Skip to content

📦 Packages & Modules

"Good fences make good neighbors."
Go's module system provides reproducible builds và clear dependency boundaries.

🏗️ Package Fundamentals

Package là gì?

Package là đơn vị tổ chức code trong Go:

go
// file: mathutil/calc.go
package mathutil  // Package declaration

import "fmt"      // Import other packages

// Exported (uppercase) - accessible from other packages
func Add(a, b int) int {
    return a + b
}

// unexported (lowercase) - package-private
func helper() {
    fmt.Println("internal")
}

Package Naming Conventions

🎓 Professor Tom's Standards

RuleExampleAvoid
Lowercase, single wordhttp, jsonhttpUtil, JSON
No underscoresstrconvstr_conv
Short, descriptiveio, osinputoutput
Match directory namepkg/auth/package authMismatch
project/
├── cmd/
│   └── server/
│       └── main.go          // package main
├── internal/
│   ├── auth/
│   │   └── auth.go          // package auth
│   └── storage/
│       └── postgres.go      // package storage
└── pkg/
    └── validator/
        └── validator.go     // package validator

📋 Go Modules Deep Dive

Initializing a Module

bash
# Create new module
$ mkdir myproject && cd myproject
$ go mod init github.com/username/myproject

# go.mod created:
module github.com/username/myproject

go 1.22

go.mod Anatomy

go
module github.com/hpn/penrift

go 1.22

require (
    github.com/spf13/cobra v1.8.0      // Direct dependency
    github.com/spf13/viper v1.18.2
    go.uber.org/zap v1.26.0
)

require (
    github.com/fsnotify/fsnotify v1.7.0 // indirect
    github.com/hashicorp/hcl v1.0.0     // indirect
    // ... transitive dependencies
)

// Replace for local development
replace github.com/myorg/shared => ../shared

// Exclude problematic version
exclude github.com/broken/pkg v1.2.3

go.sum: Integrity Verification

github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22uj9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
  • h1:: SHA-256 hash của module content
  • /go.mod: Hash của go.mod file specifically
  • Purpose: Cryptographic verification, prevent tampering

🔄 Version Semantics

Semantic Versioning (SemVer)

v1.2.3
│ │ │
│ │ └── PATCH: Bug fixes, no API changes
│ └──── MINOR: New features, backward compatible
└────── MAJOR: Breaking changes

Import Compatibility Rule

🔥 Critical: Major Version > 1

go
// v1.x.x - normal import
import "github.com/pkg/errors"

// v2.x.x - path includes major version!
import "github.com/pkg/errors/v2"

// v0.x.x - no stability guarantee
import "github.com/experimental/pkg"

Tại sao? Cho phép cùng project dùng cả v1 và v2 simultaneously.

Version Selection

bash
# Get latest
$ go get github.com/pkg/errors@latest

# Specific version
$ go get github.com/pkg/errors@v0.9.1

# Specific commit
$ go get github.com/pkg/errors@abc123

# Branch
$ go get github.com/pkg/errors@main

# Upgrade all
$ go get -u ./...

# Upgrade patch versions only
$ go get -u=patch ./...

🔒 Internal Packages

The internal Directory

Code trong internal/ chỉ importable bởi parent tree:

github.com/myorg/myproject/
├── cmd/
│   └── server/
│       └── main.go       // CAN import internal/*
├── internal/
│   └── secret/
│       └── crypto.go     // Package secret
└── pkg/
    └── public/
        └── api.go        // CANNOT import internal/*

// Bên ngoài project:
// import "github.com/myorg/myproject/internal/secret"
// ❌ Compile error: use of internal package not allowed

Use Cases

go
// internal/config/config.go
package config

// Internal implementation - không expose ra ngoài
type AppConfig struct {
    DBHost     string
    DBPassword string  // Sensitive - should not be in public API
    APIKeys    map[string]string
}

func Load() (*AppConfig, error) {
    // ...
}

📂 Vendoring

When to Vendor

ScenarioVendor?Reason
Open source libraryNoUsers have their own deps
Production serviceMaybeReproducibility, offline builds
Air-gapped environmentYesNo network access
MonorepoNoModule cache sufficient

Vendor Commands

bash
# Create vendor directory
$ go mod vendor

# Build using vendor
$ go build -mod=vendor ./...

# Verify vendor integrity
$ go mod verify

# Structure:
vendor/
├── github.com/
   └── spf13/
       └── cobra/
├── modules.txt          # Manifest
└── ...

🏢 Multi-Module Workspace (Go 1.18+)

go.work for Monorepos

bash
# Initialize workspace
$ go work init ./service-a ./service-b ./shared

# go.work created:
go 1.22

use (
    ./service-a
    ./service-b
    ./shared
)

Workspace Layout

workspace/
├── go.work           # Workspace file
├── service-a/
│   ├── go.mod        # module example.com/service-a
│   └── main.go
├── service-b/
│   ├── go.mod        # module example.com/service-b
│   └── main.go
└── shared/
    ├── go.mod        # module example.com/shared
    └── utils.go
go
// service-a/main.go
package main

import "example.com/shared"  // Uses local version automatically

func main() {
    shared.DoSomething()
}

⚔️ Tradeoff: Dependency Management Strategies

StrategyProsConsWhen to Use
Module Proxy (default)Fast, cached, secureRequires networkStandard development
VendoringOffline builds, pinned versionsRepo size increaseCI/CD, air-gapped
go.workEasy local dev, multi-moduleNot for productionMonorepo development
Replace directiveQuick local overridesMust remove before releaseDebugging, testing

💻 Engineering Example: Production Module Setup

bash
# Project structure
myservice/
├── go.mod
├── go.sum
├── cmd/
   └── server/
       └── main.go
├── internal/
   ├── config/
   └── config.go
   ├── handler/
   └── handler.go
   └── repository/
       └── user.go
├── pkg/
   └── api/
       └── types.go      # Public API types
└── Makefile

go.mod Best Practices

go
module github.com/hpn/myservice

go 1.22

// Group by purpose
require (
    // Web framework
    github.com/go-chi/chi/v5 v5.0.11
    
    // Database
    github.com/jackc/pgx/v5 v5.5.1
    
    // Observability
    go.uber.org/zap v1.26.0
    go.opentelemetry.io/otel v1.21.0
    
    // Config
    github.com/spf13/viper v1.18.2
)

// Indirect deps managed by go mod tidy
require (
    // ... auto-managed
)

Makefile for Module Management

makefile
.PHONY: deps deps-upgrade deps-verify deps-tidy

# Download dependencies
deps:
	go mod download

# Upgrade all dependencies
deps-upgrade:
	go get -u ./...
	go mod tidy

# Upgrade patch versions only (safer)
deps-upgrade-patch:
	go get -u=patch ./...
	go mod tidy

# Verify checksums
deps-verify:
	go mod verify

# Clean up unused
deps-tidy:
	go mod tidy
	go mod verify

# Security scan
deps-audit:
	go list -json -m all | nancy sleuth
	govulncheck ./...

Ship-to-Prod Checklist

Module Setup

  • [ ] go.mod đúng module path (matches repo URL)
  • [ ] go.sum committed to version control
  • [ ] Go version specified và team-aligned
  • [ ] No replace directives trong production code

Dependency Management

  • [ ] go mod tidy chạy trước mỗi commit
  • [ ] go mod verify passed
  • [ ] Dependency audit với govulncheck
  • [ ] Major version upgrades reviewed manually

Code Organization

  • [ ] Sensitive code trong internal/
  • [ ] Public APIs trong pkg/
  • [ ] Clear package boundaries
  • [ ] No import cycles

CI/CD

  • [ ] go mod download trong build pipeline
  • [ ] Cache $GOPATH/pkg/mod giữa builds
  • [ ] Vendor if offline builds needed
  • [ ] Automated dependency updates (Dependabot/Renovate)

📊 Summary

ConceptKey Point
PackageUnit of code organization, directory = package
ModuleCollection of packages with versioning
go.modModule definition, dependencies
go.sumCryptographic checksums for integrity
internal/Private packages, not externally importable
VersioningSemVer; v2+ requires path change
go.workMulti-module local development

➡️ Tiếp theo

Module system nắm vững rồi! Tiếp theo: Goroutines & Channels - Concurrent programming trong Go.