Golang Enterprise Patterns
aiskillstore/marketplace
Enterprise-level Go architecture patterns including clean architecture, hexagonal architecture, DDD, and production-ready application structure.
Enseña Domain-Driven Design y Clean Architecture de forma guiada usando Goca CLI.
$ npx skills add sazardev/goca --skill ddd-teaching-skill -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install sazardev/goca ddd-teaching-skill --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/sazardev/goca.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/ddd-teaching-skill .claude/skills/ddd-teaching-skill && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "ddd-teaching-skill" agent skill from https://github.com/sazardev/goca/tree/master/skills/ddd-teaching-skill into .claude/skills/ddd-teaching-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ddd-teaching-skill", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/sazardev/goca/tree/master/skills/ddd-teaching-skillType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add sazardev/goca --skill ddd-teaching-skill -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install sazardev/goca ddd-teaching-skill --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/sazardev/goca.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/ddd-teaching-skill .agents/skills/ddd-teaching-skill && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "ddd-teaching-skill" agent skill from https://github.com/sazardev/goca/tree/master/skills/ddd-teaching-skill into .agents/skills/ddd-teaching-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ddd-teaching-skill", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add sazardev/goca --skill ddd-teaching-skill -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install sazardev/goca ddd-teaching-skill --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/sazardev/goca.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/ddd-teaching-skill .cursor/skills/ddd-teaching-skill && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "ddd-teaching-skill" agent skill from https://github.com/sazardev/goca/tree/master/skills/ddd-teaching-skill into .cursor/skills/ddd-teaching-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ddd-teaching-skill", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/sazardev/goca.git --path skills/ddd-teaching-skill--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add sazardev/goca --skill ddd-teaching-skill -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install sazardev/goca ddd-teaching-skill --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/sazardev/goca.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/ddd-teaching-skill .gemini/skills/ddd-teaching-skill && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "ddd-teaching-skill" agent skill from https://github.com/sazardev/goca/tree/master/skills/ddd-teaching-skill into .gemini/skills/ddd-teaching-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ddd-teaching-skill", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install sazardev/goca ddd-teaching-skillInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add sazardev/goca --skill ddd-teaching-skill -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/sazardev/goca.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/ddd-teaching-skill .github/skills/ddd-teaching-skill && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "ddd-teaching-skill" agent skill from https://github.com/sazardev/goca/tree/master/skills/ddd-teaching-skill into .github/skills/ddd-teaching-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ddd-teaching-skill", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add sazardev/goca --skill ddd-teaching-skill -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install sazardev/goca ddd-teaching-skill --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/sazardev/goca.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/ddd-teaching-skill .opencode/skills/ddd-teaching-skill && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "ddd-teaching-skill" agent skill from https://github.com/sazardev/goca/tree/master/skills/ddd-teaching-skill into .opencode/skills/ddd-teaching-skill/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ddd-teaching-skill", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
ddd-teaching-skillEnseña Domain-Driven Design y Clean Architecture de forma guiada usando Goca CLI.
Ddd Teaching Skill is an agent skill from sazardev/goca. Enseña Domain-Driven Design y Clean Architecture de forma guiada usando Goca CLI. Actívar cuando el usuario pregunte "aprender DDD", "como usar Goca", "enseñame Clean Architecture", "que es domain", "como generar entity/usecase/repository/handler", o pida practicar DDD con Goca. Inactívar al completar el flujo o si el usuario cambia a tareas no relacionadas con aprendizaje.
Its SKILL.md is about 5.3k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development, covering Domain-driven design and Design patterns. It works with Go. The repository describes itself as: Goca is a powerful CLI code generator for Go that helps you create Clean Architecture projects following best practices. The licence is MIT.
Read from SKILL.md and the folder at commit 6e7138e. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
goFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Ddd Teaching Skill loads about 5.3k tokens when it runs. Until then it costs about 99 tokens; SKILL.md has 1,001 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from sazardev/goca at commit 6e7138e, republished under its MIT licence (© sazardev). 1,001 words, ~5,315 tokens.
.claude/skills/ddd-teaching-skill/SKILL.md (or your agent's skills folder).DDD + Clean Architecture resuelven el problema de código que muere lentamente: lógica de negocio mezclada con frameworks, tests imposibles, cambios que cascada. La solución es la Dependency Rule — las dependencias apuntan hacia adentro.
Goca materializa esta arquitectura generando código en 4 capas:
Handler (adapter) → UseCase (app logic) → Repository (persistence) → Domain (pure)
↓ ↓ ↓ ↓
HTTP/gRPC business logic SQL/Redis entitiesCada capa solo conoce la que está inmediatamente dentro de ella, y siempre a través de interfaces.
Invocar este skill automáticamente cuando el usuario:
| Concepto DDD | Comando Goca | Archivo generado | Propósito |
|---|---|---|---|
| Entidad | goca entity | internal/domain/product.go | Pureza del dominio, invariantes |
| Value Object | goca entity --validation | domain/product.go — Validate() | Validación encapsulada |
| Repository interface | goca repository --interface-only | repository/interfaces.go | Contrato de persistencia |
| Repository impl | goca repository -d postgres | repository/postgres_product.go | GORM encapsulado |
| DTO / Application Service | goca usecase | usecase/dto.go, service.go | Separación capas |
| UseCase interface | goca usecase | usecase/product_usecase.go | Contrato para handlers |
| Handler / Adapter | goca handler -t http | handler/http/product_handler.go | Delivery |
| DI Container | goca di | di/container.go | Wiring |
Cada paso: Concepto DDD → Comando Goca → Código generado → Test
Concepto: Separación en capas limpias. El directorio internal/ es la frontera — nada fuera de internal/ puede importar lo de adentro, pero lo de adentro sí puede importar pkg/.
Comando:
goca init ecommerce --module github.com/myapp/ecommerce --database postgresEstructura generada:
internal/
domain/ ← Puro: sin imports externos, solo lógica de negocio
usecase/ ← Solo importa domain + repository interfaces
repository/ ← Implementa interfaces; conoce GORM, no el usecase
handler/ ← Conoce interfaces de usecase, nunca repository directoAnálisis: Cada carpeta corresponde exactamente a un círculo de Clean Architecture. La regla de dependencia se aplica a nivel de import: handler → usecase → repository → domain. Prohibido saltar capas.
Test:
cd ecommerce && go build ./... && go vet ./...
# Debe pasar sin errores: es el esqueleto vacío pero correctoConcepto: Una entidad DDD tiene identidad (ID) e invariantes — reglas que siempre deben cumplirse. Los Value Objects son inmutables y se comparan por valor. Ambos viven en domain/ sin dependencias externas.
Comando:
goca entity Product --fields "name:string,price:float64,category:string" --validation --business-rulesCódigo generado (extraído de cmd/templates.go y cmd/template_components.go):
// internal/domain/product.go
package domain
type Product struct {
ID int `json:"id" gorm:"primaryKey"`
Name string `json:"name" gorm:"type:varchar(255);not null"`
Price float64 `json:"price" gorm:"type:decimal(10,2);not null"`
Category string `json:"category" gorm:"type:varchar(100)"`
}
func (p *Product) Validate() error {
if p.Name == "" {
return errors.New("product name is required")
}
if p.Price <= 0 {
return errors.New("product price must be positive")
}
return nil
}
func (p *Product) IsExpensive() bool {
return p.Price > 1000
}// internal/domain/errors.go
package domain
import "errors"
var (
ErrInvalidProductName = errors.New("product name is required")
ErrInvalidProductPrice = errors.New("product price must be positive")
)Análisis:
Product: sin lógica externa. Los tags de campo son metadata de serialización, no comportamiento.Validate(): invariante expresado como método del dominio. Sin dependencias externas. Sin ORM. Sin HTTP.IsExpensive(): regla de negocio co-localizada con los datos. Cambia la regla? Cambias este método, no un service remoto.var Err...), no strings mágicos. El consumidor puede hacer errors.Is(err, domain.ErrInvalidProductName).Test (TDD primero):
// internal/domain/product_test.go
func TestProduct_Validate(t *testing.T) {
tests := []struct {
name string
product Product
wantErr bool
}{
{"valid product", Product{Name: "Laptop", Price: 999.99, Category: "Electronics"}, false},
{"empty name", Product{Price: 999.99}, true},
{"zero price", Product{Name: "Laptop", Price: 0}, true},
{"negative price", Product{Name: "Laptop", Price: -1}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.product.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Validate() error = %v, wantErr = %v", err, tt.wantErr)
}
})
}
}
func TestProduct_IsExpensive(t *testing.T) {
cheap := Product{Name: "Notebook", Price: 10}
expensive := Product{Name: "MacBook", Price: 2500}
if cheap.IsExpensive() {
t.Error("expected cheap product to not be expensive")
}
if !expensive.IsExpensive() {
t.Error("expected expensive product to be expensive")
}
}Concepto: El Application Service orquesta la lógica de negocio. No contiene reglas de dominio (esas van en la entidad). Usa DTOs para desacoplar el mundo exterior del dominio. Depende de interfaces de repositorio, no de implementaciones concretas.
Comando:
goca usecase ProductService --entity Product --operations "create,read,update,delete,list"Código generado (extraído de cmd/template_components.go + cmd/templates.go):
// internal/usecase/product_usecase.go
package usecase
import (
"github.com/myapp/ecommerce/internal/domain"
"github.com/myapp/ecommerce/internal/repository"
)
type ProductUseCase interface {
CreateProduct(input CreateProductInput) (*CreateProductOutput, error)
GetProductByID(id int) (*ProductOutput, error)
UpdateProduct(id int, input UpdateProductInput) error
DeleteProduct(id int) error
ListProducts() (*ListProductsOutput, error)
}
type productService struct {
repo repository.ProductRepository
}
func NewProductService(repo repository.ProductRepository) ProductUseCase {
return &productService{repo: repo}
}
func (s *productService) CreateProduct(input CreateProductInput) (*CreateProductOutput, error) {
product := domain.Product{
Name: input.Name,
Price: input.Price,
Category: input.Category,
}
if err := product.Validate(); err != nil {
return nil, err
}
if err := s.repo.Save(&product); err != nil {
return nil, err
}
return &CreateProductOutput{
Product: &product,
Message: "Product created successfully",
}, nil
}// internal/usecase/dto.go
type CreateProductInput struct {
Name string `json:"name"`
Price float64 `json:"price"`
Category string `json:"category"`
}
type CreateProductOutput struct {
Product *domain.Product `json:"product"`
Message string `json:"message"`
}
type UpdateProductInput struct {
Name *string `json:"name,omitempty"`
Price *float64 `json:"price,omitempty"`
Category *string `json:"category,omitempty"`
}
type ProductOutput struct {
Product *domain.Product `json:"product"`
}
type ListProductsOutput struct {
Products []domain.Product `json:"products"`
Total int `json:"total"`
}// internal/usecase/interfaces.go
package usecase
import "github.com/myapp/ecommerce/internal/domain"
type ProductRepository interface {
Save(product *domain.Product) error
FindByID(id int) (*domain.Product, error)
Update(product *domain.Product) error
Delete(id int) error
FindAll() ([]domain.Product, error)
}Análisis:
ProductUseCase es interfaz pública. El handler programa contra esta interfaz, no contra el struct concreto.productService es privado (minúscula). Solo se exporta el constructor NewProductService(repo). Nadie puede acoplar al tipo concreto.sql.Open(), no sabe si es Postgres o Mock.CreateProductInput vs domain.Product: el input puede tener validaciones distintas al domain. El Update usa punteros (*string) para distinguir "no enviado" de "enviado vacío".ProductRepository en usecase/interfaces.go es la misma que en repository/interfaces.go. El usecase la necesita para su firma.Test con Mock (TDD — RED antes de implementar):
// internal/usecase/product_service_test.go
func TestCreateProduct_Success(t *testing.T) {
mockRepo := new(MockProductRepository)
mockRepo.On("Save", mock.AnythingOfType("*domain.Product")).Return(nil)
svc := NewProductService(mockRepo)
input := CreateProductInput{Name: "Laptop", Price: 999.99, Category: "Electronics"}
output, err := svc.CreateProduct(input)
assert.NoError(t, err)
assert.NotNil(t, output.Product)
assert.Equal(t, "Laptop", output.Product.Name)
assert.Equal(t, "Product created successfully", output.Message)
mockRepo.AssertExpectations(t)
}
func TestCreateProduct_InvalidData(t *testing.T) {
mockRepo := new(MockProductRepository)
svc := NewProductService(mockRepo)
input := CreateProductInput{Name: "", Price: 0}
_, err := svc.CreateProduct(input)
assert.Error(t, err)
mockRepo.AssertNotCalled(t, "Save")
}Concepto: El Repository Pattern abstrae el almacenamiento detrás de una interfaz. El dominio y el usecase conocen la interfaz, no la implementación. GORM, SQL, Redis, MongoDB — todo queda encapsulado detrás de esta interfaz.
Comando:
goca repository Product --database postgres --transactionsCódigo generado (extraído de cmd/templates.go + cmd/repository.go):
// internal/repository/interfaces.go
package repository
import "github.com/myapp/ecommerce/internal/domain"
type ProductRepository interface {
Save(product *domain.Product) error
FindByID(id int) (*domain.Product, error)
Update(product *domain.Product) error
Delete(id int) error
FindAll() ([]domain.Product, error)
}// internal/repository/postgres_product_repository.go
package repository
import (
"gorm.io/gorm"
"github.com/myapp/ecommerce/internal/domain"
)
type postgresProductRepository struct {
db *gorm.DB
}
func NewPostgresProductRepository(db *gorm.DB) ProductRepository {
return &postgresProductRepository{db: db}
}
func (r *postgresProductRepository) Save(product *domain.Product) error {
return r.db.Create(product).Error
}
func (r *postgresProductRepository) FindByID(id int) (*domain.Product, error) {
var product domain.Product
if err := r.db.First(&product, id).Error; err != nil {
return nil, err
}
return &product, nil
}
func (r *postgresProductRepository) Update(product *domain.Product) error {
return r.db.Save(product).Error
}
func (r *postgresProductRepository) Delete(id int) error {
return r.db.Delete(&domain.Product{}, id).Error
}
func (r *postgresProductRepository) FindAll() ([]domain.Product, error) {
var products []domain.Product
if err := r.db.Find(&products).Error; err != nil {
return nil, err
}
return products, nil
}Análisis:
repository/interfaces.go define el contrato. El usecase la consume. El handler ni la conoce.postgresProductRepository es privado — nadie fuera del package la instancia excepto el DI container.NewPostgresProductRepository(db *gorm.DB) ProductRepository devuelve la interfaz, no el struct.--transactions agrega SaveWithTx(tx *gorm.DB, ...) para Unit of Work.Concepto: El Adapter convierte requests externos (HTTP, gRPC, CLI) en llamadas a usecase. No contiene lógica de negocio. Solo serialización, routing, delegación.
Comando:
goca handler Product --type http --validationCódigo generado (extraído de cmd/templates.go):
// internal/handler/http/product_handler.go
package http
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/myapp/ecommerce/internal/usecase"
)
type ProductHandler struct {
usecase usecase.ProductUseCase
}
func NewProductHandler(uc usecase.ProductUseCase) *ProductHandler {
return &ProductHandler{usecase: uc}
}
func (h *ProductHandler) CreateProduct(w http.ResponseWriter, r *http.Request) {
var input usecase.CreateProductInput
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
output, err := h.usecase.CreateProduct(input)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(output)
}
func (h *ProductHandler) GetProduct(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id, err := strconv.Atoi(vars["id"])
if err != nil {
http.Error(w, "Invalid product ID", http.StatusBadRequest)
return
}
output, err := h.usecase.GetProductByID(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(output)
}// internal/handler/http/routes.go
package http
import (
"github.com/gorilla/mux"
"github.com/myapp/ecommerce/internal/usecase"
)
func SetupProductRoutes(router *mux.Router, uc usecase.ProductUseCase) {
handler := NewProductHandler(uc)
router.HandleFunc("/products", handler.CreateProduct).Methods("POST")
router.HandleFunc("/products/{id}", handler.GetProduct).Methods("GET")
router.HandleFunc("/products/{id}", handler.UpdateProduct).Methods("PUT")
router.HandleFunc("/products/{id}", handler.DeleteProduct).Methods("DELETE")
router.HandleFunc("/products", handler.ListProducts).Methods("GET")
}Análisis:
usecase solo. No importa repository, no importa gorm. ✅ProductHandler recibe usecase.ProductUseCase (interfaz), no el service concreto.usecase y domain no se tocan.Routes se inyecta el usecase y construye el handler — el router no necesita saber cómo construirlo.Test con httptest:
func TestCreateProductHandler(t *testing.T) {
mockUC := new(MockProductUseCase)
mockUC.On("CreateProduct", mock.Anything).Return(&usecase.CreateProductOutput{
Product: &domain.Product{Name: "Laptop", Price: 999.99},
Message: "Product created successfully",
}, nil)
handler := NewProductHandler(mockUC)
body := `{"name":"Laptop","price":999.99,"category":"Electronics"}`
req := httptest.NewRequest(http.MethodPost, "/products", strings.NewReader(body))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
handler.CreateProduct(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
assert.Contains(t, w.Body.String(), "Laptop")
mockUC.AssertExpectations(t)
}Concepto: El Composition Root es el único lugar donde se instancian implementaciones concretas. Construye el grafo de objetos completo. Todas las demás capas reciben sus dependencias ya construidas.
Comando:
goca di --features "Product" --database postgresCódigo generado (extraído de cmd/di.go):
// internal/di/container.go
package di
import (
"gorm.io/gorm"
"github.com/myapp/ecommerce/internal/repository"
"github.com/myapp/ecommerce/internal/usecase"
"github.com/myapp/ecommerce/internal/handler/http"
)
type Container struct {
db *gorm.DB
productRepo repository.ProductRepository
productUC usecase.ProductUseCase
productHandler *http.ProductHandler
}
func NewContainer(db *gorm.DB) *Container {
c := &Container{db: db}
c.setupRepositories()
c.setupUseCases()
c.setupHandlers()
return c
}
func (c *Container) setupRepositories() {
c.productRepo = repository.NewPostgresProductRepository(c.db)
}
func (c *Container) setupUseCases() {
c.productUC = usecase.NewProductService(c.productRepo)
}
func (c *Container) setupHandlers() {
c.productHandler = http.NewProductHandler(c.productUC)
}
func (c *Container) ProductHandler() *http.ProductHandler {
return c.productHandler
}Análisis:
NewContainer(db) recibe la conexión a BD. El container construye TODO el grafo.NewPostgresProductRepository, NewProductService, NewProductHandler.setupRepositories.ProductHandler()) exponen solo lo que main.go necesita.goca feature Product --fields "name:string,price:float64,category:string" --database postgres --validation --handlers httpEste comando ejecuta Pasos 2-6 en una sola operación. Equivale a:
1. goca entity Product --fields "name:string,price:float64,category:string" --validation --business-rules
2. goca usecase ProductService --entity Product --operations "create,read,update,delete,list"
3. goca repository Product --database postgres
4. goca handler Product --type http --validation
5. goca messages Product --all
6. goca di --features "Product" --database postgresAdemás integra el handler en main.go y registra migraciones automáticas.
❌ Handler importando repository directamente
type ProductHandler struct {
repo *gorm.DB // MAL: handler conoce la BD y GORM!
}✅ Handler solo conoce usecase.ProductUseCase
❌ UseCase con GORM o SQL
type productService struct {
db *gorm.DB // MAL: lógica de negocio conoce GORM
}✅ UseCase recibe repository.ProductRepository (interfaz abstracta)
❌ Entidad anémica (solo getters/setters, sin comportamiento)
type Product struct {
Name string // MAL: sin Validate(), sin reglas de negocio
Price float64 // solo es una struct de datos, no una entidad DDD
}✅ Domain tiene métodos: Validate(), IsExpensive(), etc.
❌ DTOs expuestos desde handler — usa usecase.CreateProductInput, no crees DTOs en handler.
❌ init() y variables globales — usa constructor injection siempre.
Este skill enseña DDD + Clean Architecture a través de Goca. Para otros aspectos, delegar:
| Necesitas | Recurso |
|---|---|
| Benchmarks, fuzzing, test coverage avanzado | golang-testing skill |
| Table-driven tests, helpers, golden files | golang-testing skill |
| sync.Pool, zero allocation, performance | golang-performance skill |
| Interface design, functional options, patterns | golang-patterns skill |
| Validar dependencias entre capas archivo por archivo | ArchitectGuard agent mode en .github/AGENTS.md |
| Verificar que templates generan código compilable | CodegenAuditor agent mode en .github/AGENTS.md |
| Guía completa de comandos Goca | GUIDE.md |
Cuando el usuario cambie a una tarea no relacionada con aprendizaje DDD (ej: "arregla este bug", "agrega esta feature"), desactivar este skill y continuar como agente normal.
© sazardev, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/ddd-teaching-skill of sazardev/goca.
Open the folder on GitHubat commit 6e7138e
Ddd Teaching Skill next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Ddd Teaching Skill this skillsazardev/goca | 298 | — | ~5.3k | Automated safety check: Pass | MIT | |
| Golang Enterprise Patternsaiskillstore/marketplace | 430 | 1 repos | ~2.2k | Automated safety check: Pass | None | |
| Golang Project Layoutcontext-labs/whip | 1.1k | 1 repos | ~1.8k | Automated safety check: Pass | MIT | |
| Context Handling in fp-goIBM/fp-go | 2k | — | ~4.2k | Automated safety check: Pass | Apache-2.0 | |
| Typed Dependencies with fp-go EffectIBM/fp-go | 2k | — | ~4.3k | Automated safety check: Pass | Apache-2.0 | |
| Scaffoldcodewithmukesh/dotnet-claude-kit | 751 | — | ~1.7k | Automated safety check: Pass | MIT |
aiskillstore/marketplace
Enterprise-level Go architecture patterns including clean architecture, hexagonal architecture, DDD, and production-ready application structure.
context-labs/whip
Golang project layouts and workspaces. An agent skill from context-labs/whip.
IBM/fp-go
Covers handling Go's context.Context idiomatically in fp-go code: reading and scoping context through operators, timeouts, cancellation and converting ctx-first functions.
IBM/fp-go
Teaches an agent to write fp-go v2 services with the Effect type, carrying dependencies in its type parameter instead of in context.Context or parameters.
codewithmukesh/dotnet-claude-kit
Architecture-aware feature scaffolding for .NET 10 projects.
codewithmukesh/dotnet-claude-kit
Architecture selection advisor for .NET applications. An agent skill from codewithmukesh/dotnet-claude-kit.
Works with
Categories
Enseña Domain-Driven Design y Clean Architecture de forma guiada usando Goca CLI. Ddd Teaching Skill is an agent skill from sazardev/goca. Enseña Domain-Driven Design y Clean Architecture de forma guiada usando Goca CLI.
Ddd Teaching Skill fits situations like: tasks that involve Domain-driven design; tasks that involve Design patterns.
Run `npx skills add sazardev/goca --skill ddd-teaching-skill -a claude-code`. Or copy the skill folder (skills/ddd-teaching-skill in sazardev/goca) into .claude/skills/ddd-teaching-skill in your project. Claude Code loads it when a task matches its description.
Run `npx skills add sazardev/goca --skill ddd-teaching-skill -a codex`. Or copy the skill folder (skills/ddd-teaching-skill in sazardev/goca) into .agents/skills/ddd-teaching-skill in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add sazardev/goca --skill ddd-teaching-skill -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/ddd-teaching-skill, .gemini/skills/ddd-teaching-skill, .github/skills/ddd-teaching-skill and .opencode/skills/ddd-teaching-skill in your project.
Going by SKILL.md and its folder, Ddd Teaching Skill needs the command-line tools its instructions call (go).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Ddd Teaching Skill is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 5.3k tokens (SKILL.md is roughly 21k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Ddd Teaching Skill: Golang Enterprise Patterns (aiskillstore/marketplace, 430 stars), Golang Project Layout (context-labs/whip, 1.1k stars), Context Handling in fp-go (IBM/fp-go, 2k stars) and Typed Dependencies with fp-go Effect (IBM/fp-go, 2k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
sazardev (a GitHub user) maintains it in sazardev/goca, which has 298 GitHub stars. The repository was last updated on July 20, 2026.
Source: sazardev/goca on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.