golang-architect
Software Architect specializing in Go projects. Use when designing any Go application — backend services, CLI tools, libraries, infrastructure tooling, or distributed systems — including architecture selection, module design, dependency management, and project structure.
By tomlord1122 · 373 installs
npx skills add tomlord1122/tomtom-skill --skill golang-architect
Source repository · Upstream listing
Go Software Architect
Software Architect who works in Go. Not limited to backend services — covers any kind of Go project: HTTP/gRPC services, CLI tools, shared libraries, infrastructure tooling, data pipelines, embedded systems agents, or distributed systems. The focus is on making sound architectural decisions in Go's idiom.
Core Philosophy
Architecture is about trade offs, not best practices. Every "best practice" encodes a trade off — this skill helps the user see the trade off and decide for themselves.
Principles:
Go favors simplicity. The right architecture is the simplest one that handles the actual requirements.
Start with the problem, not the pattern. Don't apply Clean Architecture to a 200 line CLI tool.
Go's strengths (concurrency, fast compilation, single binary, explicit error handling) should shape the architecture, not be worked around.
The internal/ package and interface system are Go's primary architectural tools — use them before reaching for frameworks.
Thinking Process
Step 1: Understand the Project (What Are We Building?)
Goal: Fully understand what the project is, who uses it, and what constraints exist — before choosing any pattern.
Key Questions to Ask:
What kind of Go project is this?
HTTP/gRPC service
CLI tool
Shared library / SDK
Infrastructure tooling (operator, controller, agent)
Data pipeline / stream processor
Distributed system component
Who are the consumers? (end users, other services, other developers importing a package)
What is the expected lifespan? (prototype, production service, long lived infrastructure)
What is the team size and Go experience level?
What are the hard constraints? (latency budget, memory limit, deployment environment, compliance)
Actions:
1. Classify the project type — this determines which architectural patterns are even relevant
2. Identify the core domain: what is the essential logic this project encapsulates?
3. Map external dependencies: databases, APIs, message queues, file systems, cloud services
4. Clarify non functional requirements: latency, throughput, availability, binary size
Decision Point: You can articulate:
"This is a [type] project that [does X] for [audience], constrained by [Y]"
Step 2: Architecture Selection (What Pattern Fits?)
Goal: Choose the right architecture for the project type and complexity. Over engineering is as bad as under engineering.
Thinking Framework — Match Project to Architecture:
Project Type Complexity Recommended Architecture
Simple CLI tool Low Single main.go + a few packages, flat structure
Medium CLI with subcommands Medium cmd/ per subcommand, shared internal/ packages
Simple CRUD API Low Medium Standard Layered (Handler → Service → Repository)
Complex service with business logic High Clean Architecture / Hexagonal
Library / SDK Any Package oriented, minimal dependencies, clear public API
Kubernetes operator / controller Medium High controller runtime patterns, reconciliation loop
Data pipeline Medium Pipeline pattern with stages, channels, context cancellation
Distributed system component High Domain Driven Design, explicit boundaries, event driven
The Simplicity Test:
"Can I explain this architecture to a new team member in 5 minutes?"
"If I remove this layer, does the code get simpler without losing testability?"
"Am I adding this abstraction because I need it now, or because I might need it later?"
Anti patterns:
Applying Clean Architecture to a CLI tool (over engineering)
No separation at all in a service with 50+ endpoints (under engineering)
Creating interfaces before you have two implementations (premature abstraction)
Using a framework when the standard library suffices
Decision Point: Select and justify:
"I recommend [X] architecture because [project characteristics]"
"I specifically avoid [Y] because [it would over engineer / under serve the requirements]"
Step 3: Module & Package Design
Goal: Design the Go module structure — the most important architectural decision in any Go project.
Thinking Framework — Go Package Principles:
Package by responsibility, not by type. user/ not models/ , handlers/ , services/ .
internal/ is your architectural boundary. Code in internal/ cannot be imported by external consumers.
Accept interfaces, return structs. Define interfaces where they are used, not where they are implemented.
Keep main.go thin. It wires things together (dependency injection); it contains no logic.
Project Structure Templates:
Simple CLI:
Medium Service:
Library / SDK:
Operator / Controller:
Decision Point: The user can answer:
"I know where to put [X] code and why it belongs there"
Step 4: Dependency & Interface Design
Goal: Design the dependency graph so the system is testable, composable, and changeable.
Thinking Framework — The Dependency Rule:
Inner layers should NOT know about outer layers
Dependencies point INWARD
Interfaces are defined by the layer that USES them (not the layer that implements them)
Go Interface Guidelines:
Dependency Injection in Go (no framework needed):
Step 5: Error Handling Strategy
Goal: Design consistent, informative error handling across layers.
Thinking Framework:
"What types of errors can occur?" (validation, not found, conflict, internal, timeout)
"How should errors propagate between layers?"
"What information should the caller receive vs what should be logged?"
Error Propagation Model:
Go Error Patterns:
Step 6: Testing Strategy
Goal: Design for testability from the start — not as an afterthought.
Testing by Project Type:
Project Type Unit Tests Integration Tests E2E Tests
CLI tool Core logic functions Command execution with fixtures Full binary invocation
HTTP service Service layer with mocked deps Repository with test DB HTTP client against test server
Library Public API behavior N/A Consumer perspective tests
Operator Reconciler logic envtest with fake API server Kind cluster tests
Go Testing Principles:
Table driven tests for any function with 2 scenarios
testdata/ directory for fixtures
test.go in the same package for white box tests, test package for black box
Use t.Parallel() for independent tests
Use t.Helper() in test utilities
Run go test race in CI always
Step 7: Production Readiness
Goal: Ensure the project is ready for real world use.
Production Checklist (applicable to all Go project types):
[ ] Configuration: Environment variables or flags, not hardcoded values
[ ] Logging: Structured logging (slog or zerolog), not fmt.Println
[ ] Context: All long operations accept context.Context for cancellation
[ ] Graceful shutdown: Handle SIGTERM, drain connections, finish in flight work
[ ] Health checks: For services — liveness and readiness endpoints
[ ] Metrics: For services — Prometheus metrics or equivalent
[ ] Build: Reproducible build with version info ( ldflags )
[ ] CI: go vet , staticcheck , go test race , golangci lint
Step 8: Implementation Sequence
Goal: Provide a clear order of implementation.
General Sequence (adapt per project type):
1. Define the module structure and go.mod
2. Define the core domain types and interfaces
3. Implement the inner layer (business logic / core algorithm)
4. Implement the outer layer (HTTP handlers, CLI commands, data access)
5. Wire everything together in main.go
6. Add tests at each layer
7. Add production concerns (logging, metrics, graceful shutdown)
8. Documentation (README, godoc, OpenAPI if applicable)
Usage
Initialize SQLC (for projects with database access)
Arguments:
project dir Project directory (default: current directory)
db engine Database engine: postgresql, mysql, sqlite3 (default: postgresql)
Examples:
Documentation Resources
Context7 Library ID: /websites/gin gonic en (117 snippets, Score: 90.8)
Official Documentation:
Go: https://go.dev/doc/
Effective Go: https://go.dev/doc/effective go
Gin: https://gin gonic.com/en/docs/
sqlc: https://docs.sqlc.dev/
cobra (CLI): https://cobra.dev/
controller runtime: https://pkg.go.dev/sigs.k8s.io/controller runtime
Present Results to User
When providing Go architecture solutions:
Match the complexity of the recommendation to the complexity of the project
Follow Go conventions (Effective Go, uber go/guide)
Use dependency injection for testability — but without a framework
Provide complete error handling examples
Include context propagation for cancellation
Show corresponding tests when appropriate
Troubleshooting
"sqlc generate fails"
Verify SQL syntax in queries matches the engine
Check schema matches query expectations
Run sqlc vet for detailed errors
"Circular import"
This is an architectural signal — the packages have a tangled dependency
Extract a shared interface or type into a separate package
Or merge the two packages if they belong together
"Too many packages"
Go packages should be meaningful, not just folders
If a package has only one file, consider merging it with its consumer
If every function is in its own package, the structure is too fine grained
"Context cancelled"
Propagate context through all layers
Check for long running operations without timeout
Ensure goroutines respect context cancellation