11 Working with Larger Projects
Go supports larger projects by giving developers a clear way to organize code at several levels, from packages to modules, versions, and workspaces. The chapter emphasizes that real applications usually depend on external libraries and services, so keeping dependencies documented and builds reproducible is essential. It also shows how a multi-module RSS reader can be structured so that separate parts of the system evolve independently while still working together cleanly.
The core design centers on a shared domain module that defines the project’s main entities and interfaces, such as articles, feeds, a fetcher, and storage. This domain layer stays stable and free of infrastructure details, while other modules provide concrete implementations. The storage module uses an embedded database and an adapter pattern to persist articles, while the API and worker depend only on the domain abstractions they need, which improves testability, flexibility, and separation of concerns.
The chapter also explains how Go handles dependency management and collaboration across modules with go.mod, go.sum, semantic versioning, and workspaces. Versions are tagged per module so each component can be released on its own schedule, and a workspace lets local modules reference one another during development without publishing every change. By combining these tools with disciplined package layout and interface-driven design, Go makes it practical to build maintainable systems that can grow without becoming tightly coupled or difficult to change.
Go’s code organization hierarchy from packages to workspaces
Complete directory structure for go-news with domain, storage, API, and worker modules
Domain-Driven Design separates core logic from infrastructure
Hexagonal Architecture: Domain at center with ports and adapters
Independent evolution: modules version at different rates based on their volatility
Workspace development workflow with local module resolution
Independent module version timelines marked by Git tags
Summary
- Packages are Go’s fundamental code organization unit with strict rules against circular dependencies, organized through directories like
cmd,internal, andpkg. - Modules group packages with semantic versioning (vMAJOR.MINOR.PATCH) tracked in
go.modfiles, working withgo.sumfor cryptographic dependency verification. - Domain-Driven Design separates core business logic (entities and interfaces) from infrastructure concerns, creating stable foundations that services depend on.
- Interface-based architecture and the Liskov Substitution Principle enable flexibility. Any implementation satisfying an interface works interchangeably, critical for testing and swapping implementations.
- Hexagonal Architecture uses ports (domain interfaces) and adapters (concrete implementations) to cleanly separate core logic from infrastructure.
- Workspaces coordinate multiple modules during development via
go.workfiles, enabling local cross-module changes without publishing versions while maintaining independent versioning. - Test doubles enable isolated unit testing by implementing domain interfaces with predetermined data, testing handlers without databases or external services.
- Dependency Inversion structures applications where high-level modules depend on domain abstractions rather than low-level details, enabling independent component evolution.
- Multi-module patterns demonstrated through our RSS reader show how clean boundaries enable natural system extension with new capabilities.
FAQ
What is the main goal of organizing a Go project into packages, modules, and workspaces?
The goal is to keep code maintainable, reusable, and easy to evolve. Packages organize code, modules group related packages with dependency tracking, and workspaces let multiple related modules be developed together while still remaining independent.Why does the chapter split the RSS reader into domain, storage, API, and worker modules?
It separates concerns so each part can change independently. The domain defines core types and interfaces, storage handles persistence, the API serves HTTP requests, and the worker fetches RSS feeds in the background.What is the purpose of the domain module in this architecture?
The domain module contains the shared business concepts, such asArticle and Feed, plus interfaces like Fetcher and Storage. It acts as the stable center of the system and depends on nothing else.Why are interfaces used in the domain instead of concrete implementations?
Interfaces describe what the system needs without tying it to a specific implementation. This makes it easy to swap libraries, test with stubs, and keep dependencies pointing inward toward the domain.What do go.mod and go.sum do?
go.mod defines the module path and its dependencies, while go.sum records cryptographic checksums to ensure the exact dependency versions are reproducible and secure.What does go mod tidy do?
It cleans up module metadata by removing unused dependencies, adding missing ones, and updating go.sum so the module files stay accurate and minimal.Why is bbolt used for storage in this chapter?
bbolt provides embedded, file-based persistence with simple key-value storage, supports multiple readers and one writer, and works well for the worker/API pattern where one service writes and another reads.Why does the API open the database in read-only mode while the worker opens it in write mode?
This enforces least privilege. The API only needs to read articles, while the worker needs to write them. It also improves safety and concurrency by letting many readers run alongside a single writer.What is a Go workspace and why is it useful here?
A workspace is ago.work file that lets multiple modules in the same repository use each other locally during development. It avoids constantly publishing versions while still keeping each module independently versioned.How do module version tags work in a multi-module repository?
Each module gets its own version tag, prefixed with the module path, such asdomain/v0.0.1 or api/v1.1.0. This lets each module evolve and be released independently.
Go in Action, Second Edition ebook for free