Lab 03: Generics Architecture

Time: 60 minutes | Level: Architect | Docker: golang:1.22-alpine

Overview

Generic architecture in Go: generic repository pattern, Result[T,E] error handling, EventBus[T] for type-safe events, generic Pipeline with Stage[I,O], type constraint composition, and generic middleware chains.


Step 1: Generic Repository Pattern

package main

import (
	"context"
	"fmt"
)

// Constraint: any ID type that supports == comparison
type Repository[T any, ID comparable] struct {
	store map[ID]T
}

func NewRepository[T any, ID comparable]() *Repository[T, ID] {
	return &Repository[T, ID]{store: make(map[ID]T)}
}

func (r *Repository[T, ID]) Save(_ context.Context, id ID, item T) error {
	r.store[id] = item
	return nil
}

func (r *Repository[T, ID]) FindByID(_ context.Context, id ID) (T, bool) {
	item, ok := r.store[id]
	return item, ok
}

func (r *Repository[T, ID]) All(_ context.Context) []T {
	items := make([]T, 0, len(r.store))
	for _, v := range r.store {
		items = append(items, v)
	}
	return items
}

func (r *Repository[T, ID]) Delete(_ context.Context, id ID) bool {
	_, ok := r.store[id]
	delete(r.store, id)
	return ok
}

func (r *Repository[T, ID]) Count() int {
	return len(r.store)
}

Step 2: Generic Result Type


Step 3: Generic EventBus


Step 4: Generic Pipeline — Stage[I,O]


Step 5: Type Constraint Composition


Step 6: Generic Middleware Chain


Step 7: Generic Cache


Step 8: Capstone — Generic Repository + EventBus

📸 Verified Output:


Summary

Pattern
Generic API
Type Safety

Repository

Repository[T, ID comparable]

Full CRUD typed

Result type

Result[T, E error]

No untyped errors

EventBus

EventBus[T]

No interface{} cast

Pipeline

Stage[I, O] + Compose

Stage chain typed

Constraints

type Ordered interface{~int|...}

Method sets

Middleware

Middleware[T, R]

Handler signature

Cache

Cache[K comparable, V any]

Type-safe K/V

Last updated