brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
advanced-patternsApplies advanced Go patterns including generics, reflection, functional options, and metaprogramming for performance-critical and framework-level code.
Independent GitHub snapshot ยท Automated classification ยท Original documentation governs
name: advanced-patterns description: Applies advanced Go patterns including generics, reflection, functional options, and metaprogramming for performance-critical and framework-level code. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: go role: implementation scope: implementation output-format: code content-types:
Senior Go engineer applying advanced language features for framework-level and performance-critical code. This skill covers generics, reflection, functional options, compile-time assertions, and safe metaprogramming.
go:embed for compile-time asset inclusion โ never hardcode file pathstype _ interface{} compile-time assertions to verify interface satisfactionunsafe unless you fully understand the memory layout and aliasing rulesUse this skill when:
go:embed)Avoid this skill for:
Choose the Right Abstraction โ Decide between interfaces, generics, or composition. Checkpoint: The abstraction adds value โ it reduces code duplication or enables type safety.
Implement the Pattern โ Write the generic function, option type, or reflection logic.
Checkpoint: Code compiles with go vet โ no type safety violations.
Add Compile-Time Assertions โ Verify that types satisfy expected interfaces. Checkpoint: Compilation fails if the interface contract is violated.
Benchmark Performance โ Ensure the pattern doesn't add unacceptable overhead. Checkpoint: Benchmark shows acceptable performance vs. the non-abstracted version.
Document the Pattern โ Explain why the pattern was chosen and how to use it. Checkpoint: Usage examples are included in godoc comments.
Generics enable type-safe code without runtime type assertions.
// โ BAD: interface{} requires runtime type assertions โ unsafe and slow
type Stack struct {
items []interface{}
}
func (s *Stack) Push(item interface{}) {
s.items = append(s.items, item)
}
func (s *Stack) Pop() interface{} {
if len(s.items) == 0 {
return nil
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item
}
// Usage requires type assertion โ easy to get wrong
func processStack() {
s := &Stack{}
s.Push("hello")
s.Push(42) // compiles โ but wrong type!
// Runtime type assertion โ panics if type is wrong
str := s.Pop().(string) // panics if the top item was 42
fmt.Println(str)
}
What's wrong:
interface{} accepts any type โ s.Push(42) compiles but is semantically wrongPop().(string) panics at runtime if the type is wronginterface{} has allocation overhead โ each value is boxed// Stack is a generic LIFO (last-in, first-out) data structure.
// The element type T is specified at construction time.
type Stack[T any] struct {
items []T
}
// NewStack creates a new generic stack.
func NewStack[T any]() *Stack[T] {
return &Stack[T]{items: make([]T, 0)}
}
// Push adds an item to the top of the stack.
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
// Pop removes and returns the top item.
// Returns zero value of T and false if the stack is empty.
func (s *Stack[T]) Pop() (T, bool) {
if len(s.items) == 0 {
var zero T
return zero, false
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item, true
}
// Len returns the number of items in the stack.
func (s *Stack[T]) Len() int {
return len(s.items)
}
// IsEmpty returns true if the stack has no items.
func (s *Stack[T]) IsEmpty() bool {
return len(s.items) == 0
}
// Usage โ type is enforced at compile time
func processStack() {
// String stack
strStack := NewStack[string]()
strStack.Push("hello")
strStack.Push("world")
str, ok := strStack.Pop()
if !ok {
log.Fatal("stack is empty")
}
fmt.Println(str) // "world"
// This would not compile โ type is enforced:
// strStack.Push(42) // โ cannot use 42 (int) as string
// Int stack โ separate type
intStack := NewStack[int]()
intStack.Push(42)
intStack.Push(100)
n, ok := intStack.Pop()
if ok {
fmt.Println(n) // 100
}
}
Why this works:
NewStack[string]() creates a string stackstrStack.Push(42) does not compilePop() returns (T, bool) โ zero value on emptyinterface{}IsEmpty(), Len(), and the (T, bool) return make usage obviousThe functional options pattern provides a clean API for constructors with many optional parameters.
// โ BAD: too many parameters โ hard to use, easy to forget required ones
type Server struct {
Addr string
Port int
Timeout time.Duration
CertFile string
KeyFile string
MaxConns int
KeepAlive bool
ReadBuf int
WriteBuf int
Debug bool
}
// Constructor with 10 parameters โ 7 optional, 3 required
func NewServer(addr string, port int, timeout time.Duration,
certFile string, keyFile string, maxConns int,
keepAlive bool, readBuf int, writeBuf int, debug bool) *Server {
// ...
}
// Usage โ which parameters are optional? What are the defaults?
// Hard to read, easy to mess up
server := NewServer("0.0.0.0", 8080, 30*time.Second,
"cert.pem", "key.pem", 100,
true, 4096, 4096, false)
What's wrong:
certFile and keyFile is a silent bug// Server provides an HTTP server with configurable options.
type Server struct {
addr string
port int
timeout time.Duration
certFile string
keyFile string
maxConns int
keepAlive bool
readBuf int
writeBuf int
debug bool
}
// Option configures a Server via functional options.
type Option func(*Server)
// WithAddr sets the server address. Default: "0.0.0.0".
func WithAddr(addr string) Option {
return func(s *Server) {
s.addr = addr
}
}
// WithPort sets the server port. Default: 8080.
func WithPort(port int) Option {
return func(s *Server) {
s.port = port
}
}
// WithTimeout sets the read/write timeout. Default: 30s.
func WithTimeout(timeout time.Duration) Option {
return func(s *Server) {
s.timeout = timeout
}
}
// WithTLS sets TLS certificate and key files.
func WithTLS(certFile, keyFile string) Option {
return func(s *Server) {
s.certFile = certFile
s.keyFile = keyFile
}
}
// WithMaxConns sets the maximum number of connections. Default: 100.
func WithMaxConns(maxConns int) Option {
return func(s *Server) {
s.maxConns = maxConns
}
}
// WithDebug enables debug logging. Default: false.
func WithDebug(enabled bool) Option {
return func(s *Server) {
s.debug = enabled
}
}
// NewServer creates a Server with the given options.
// All options are optional โ defaults are applied for unset values.
func NewServer(options ...Option) *Server {
s := &Server{
addr: "0.0.0.0",
port: 8080,
timeout: 30 * time.Second,
maxConns: 100,
readBuf: 4096,
writeBuf: 4096,
}
// Apply options in order โ last one wins for conflicting options
for _, opt := range options {
opt(s)
}
return s
}
// Usage โ clean, readable, only specify what you need
server := NewServer(
WithPort(9090),
WithTimeout(60*time.Second),
WithTLS("cert.pem", "key.pem"),
WithDebug(true),
)
// Minimal usage โ all defaults
server := NewServer()
// Override a single default
server := NewServer(WithPort(443))
Why this works:
WithPort(9090) is readableNewServerWithXxx functions don't break existing callersNewServer โ caller knows what happens with no optionsWithPort("abc") doesn't compileCompile-time assertions catch interface violations at build time. go:embed includes assets at compile time.
// โ BAD: interface satisfaction checked at runtime โ too late
type Repository interface {
Get(ctx context.Context, id string) (*User, error)
Create(ctx context.Context, user *User) error
}
type MockRepository struct{}
func (m *MockRepository) Get(ctx context.Context, id string) (*User, error) {
return nil, nil
}
// No compile-time check โ if MockRepository doesn't implement Repository,
// the error surfaces only when the code is compiled (and only if someone
// tries to assign it)
func main() {
// This would silently fail to compile if MockRepository is missing a method,
// but only at the assignment site โ no clear error message
var repo Repository = &MockRepository{}
_ = repo
}
// โ BAD: hardcoding asset paths โ breaks if files move
func loadTemplate() string {
data, err := os.ReadFile("templates/profile.html")
if err != nil {
log.Fatal(err)
}
return string(data)
}
What's wrong:
MockRepository implements Repositoryos.ReadFile at runtime โ template loading happens on every call// package: internal/user
// Compile-time interface assertion.
// This line will fail to compile if *MockRepository does NOT implement UserRepository.
var _ UserRepository = (*MockRepository)(nil)
// MockRepository implements UserRepository for testing.
type MockRepository struct {
users map[string]*User
}
func NewMockRepository() *MockRepository {
return &MockRepository{users: make(map[string]*User)}
}
func (m *MockRepository) Get(ctx context.Context, id string) (*User, error) {
user, ok := m.users[id]
if !ok {
return nil, fmt.Errorf("user %s not found", id)
}
return user, nil
}
func (m *MockRepository) Create(ctx context.Context, user *User) error {
if _, ok := m.users[user.ID]; ok {
return fmt.Errorf("user %s already exists", user.ID)
}
m.users[user.ID] = user
return nil
}
// Multiple interface assertions in one line
var (
_ UserRepository = (*MockRepository)(nil)
_ io.Reader = (*MockRepository)(nil)
_ io.Closer = (*MockRepository)(nil)
)
// package: web
//go:embed templates/*.html
var templateFS embed.FS
// templateCache holds pre-parsed templates.
var templateCache = sync.OnceValue(func() *template.Template {
tmpl := template.Must(template.New("").ParseFS(templateFS, "templates/*.html"))
return tmpl
})
// renderProfile renders the user profile page.
func renderProfile(w http.ResponseWriter, user *User) {
tmpl := templateCache()
if err := tmpl.ExecuteTemplate(w, "profile.html", user); err != nil {
log.Printf("template error: %v", err)
http.Error(w, "internal error", 500)
}
}
Directory structure:
myapp/
โโโ cmd/
โ โโโ server/
โ โโโ main.go
โโโ internal/
โ โโโ user/
โ โ โโโ repository.go // UserRepository interface + MockRepository
โ โโโ web/
โ โโโ handler.go // renderProfile with go:embed
โ โโโ templates/
โ โโโ profile.html
โ โโโ list.html
โ โโโ error.html
โโโ go.mod
โโโ go.sum
Why this works:
var _ UserRepository = (*MockRepository)(nil) โ fails to compile if the mock doesn't implement the interface(*MockRepository)(nil) is never created at runtime โ it's a compile-time only check//go:embed includes HTML templates in the binary at compile time โ no runtime file readssync.OnceValue (Go 1.23+) lazily parses templates once โ zero overhead on first access, cached thereafterinterface{} when the type is known at construction//go:embed for including static assets โ never hardcode file pathsvar _ Interface = (*Type)(nil)// T is the element type)unsafe without a thorough understanding of memory layout and aliasing rulesgo:embed that change frequently โ embedded files are baked into the binary at compile timetype _ interface{} assertions in production code without a clear reason โ they add maintenance overhead| Skill | Purpose |
|---|---|
best-practices | Go idioms and code organization |
modular-design | Interface-based design that works with generics |
concurrency-patterns | Generic concurrency utilities (channels, workers) |
database-patterns | Generic repository patterns for type-safe data access |