Giao diện
📦 Packages & Modules
"Good fences make good neighbors."
Go's module system provides reproducible builds và clear dependency boundaries.
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
| Rule | Example | Avoid |
|---|---|---|
| Lowercase, single word | http, json | httpUtil, JSON |
| No underscores | strconv | str_conv |
| Short, descriptive | io, os | inputoutput |
| Match directory name | pkg/auth/ → package auth | Mismatch |
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.22go.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.3go.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 changesImport 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 allowedUse 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
| Scenario | Vendor? | Reason |
|---|---|---|
| Open source library | No | Users have their own deps |
| Production service | Maybe | Reproducibility, offline builds |
| Air-gapped environment | Yes | No network access |
| Monorepo | No | Module 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.gogo
// service-a/main.go
package main
import "example.com/shared" // Uses local version automatically
func main() {
shared.DoSomething()
}⚔️ Tradeoff: Dependency Management Strategies
| Strategy | Pros | Cons | When to Use |
|---|---|---|---|
| Module Proxy (default) | Fast, cached, secure | Requires network | Standard development |
| Vendoring | Offline builds, pinned versions | Repo size increase | CI/CD, air-gapped |
| go.work | Easy local dev, multi-module | Not for production | Monorepo development |
| Replace directive | Quick local overrides | Must remove before release | Debugging, 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
└── Makefilego.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 tidychạy trước mỗi commit - [ ]
go mod verifypassed - [ ] 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 downloadtrong build pipeline - [ ] Cache
$GOPATH/pkg/modgiữa builds - [ ] Vendor if offline builds needed
- [ ] Automated dependency updates (Dependabot/Renovate)
📊 Summary
| Concept | Key Point |
|---|---|
| Package | Unit of code organization, directory = package |
| Module | Collection of packages with versioning |
| go.mod | Module definition, dependencies |
| go.sum | Cryptographic checksums for integrity |
| internal/ | Private packages, not externally importable |
| Versioning | SemVer; v2+ requires path change |
| go.work | Multi-module local development |
➡️ Tiếp theo
Module system nắm vững rồi! Tiếp theo: Goroutines & Channels - Concurrent programming trong Go.