Use Cases

Desarrollo en Go con Claude Code

Aprenda sobre desarrollo en Go usando Claude Code. Incluye consejos practicos y ejemplos de codigo.

Ventajas de usar Claude Code en el desarrollo con Go

Go se caracteriza por su diseno de API simple, poderoso procesamiento concurrente y compilacion rapida. Claude Code comprende los modismos de Go y puede implementar con precision patrones especificos de Go como manejo de errores, goroutines y canales.

Desarrollo de Web API

> Crea una REST API con la libreria estandar de Go y el router chi.
> Incluye middleware, validacion y logging estructurado.
// main.go
package main

import (
	"context"
	"encoding/json"
	"log/slog"
	"net/http"
	"os"
	"os/signal"
	"time"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"github.com/google/uuid"
)

type Task struct {
	ID          string    `json:"id"`
	Title       string    `json:"title"`
	Description string    `json:"description,omitempty"`
	Completed   bool      `json:"completed"`
	CreatedAt   time.Time `json:"created_at"`
}

type CreateTaskRequest struct {
	Title       string `json:"title"`
	Description string `json:"description,omitempty"`
}

type TaskStore struct {
	tasks map[string]*Task
}

func NewTaskStore() *TaskStore {
	return &TaskStore{tasks: make(map[string]*Task)}
}

func main() {
	logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
	slog.SetDefault(logger)

	store := NewTaskStore()

	r := chi.NewRouter()
	r.Use(middleware.RequestID)
	r.Use(middleware.RealIP)
	r.Use(requestLogger)
	r.Use(middleware.Recoverer)
	r.Use(middleware.Timeout(30 * time.Second))

	r.Route("/api/tasks", func(r chi.Router) {
		r.Get("/", store.listTasks)
		r.Post("/", store.createTask)
		r.Route("/{id}", func(r chi.Router) {
			r.Get("/", store.getTask)
			r.Put("/", store.updateTask)
			r.Delete("/", store.deleteTask)
		})
	})

	r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
		writeJSON(w, http.StatusOK, map[string]string{"status": "ok"})
	})

	srv := &http.Server{
		Addr:         ":8080",
		Handler:      r,
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 30 * time.Second,
		IdleTimeout:  60 * time.Second,
	}

	// Apagado graceful
	go func() {
		slog.Info("Servidor iniciando", "addr", srv.Addr)
		if err := srv.ListenAndServe(); err != http.ErrServerClosed {
			slog.Error("Error del servidor", "error", err)
			os.Exit(1)
		}
	}()

	quit := make(chan os.Signal, 1)
	signal.Notify(quit, os.Interrupt)
	<-quit

	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	slog.Info("Apagando servidor...")
	if err := srv.Shutdown(ctx); err != nil {
		slog.Error("Error al apagar", "error", err)
	}
}

func (s *TaskStore) listTasks(w http.ResponseWriter, r *http.Request) {
	tasks := make([]*Task, 0, len(s.tasks))
	for _, t := range s.tasks {
		tasks = append(tasks, t)
	}
	writeJSON(w, http.StatusOK, tasks)
}

func (s *TaskStore) createTask(w http.ResponseWriter, r *http.Request) {
	var req CreateTaskRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeError(w, http.StatusBadRequest, "Cuerpo de solicitud invalido")
		return
	}

	if req.Title == "" {
		writeError(w, http.StatusBadRequest, "El titulo es obligatorio")
		return
	}

	task := &Task{
		ID:          uuid.New().String(),
		Title:       req.Title,
		Description: req.Description,
		Completed:   false,
		CreatedAt:   time.Now(),
	}

	s.tasks[task.ID] = task
	writeJSON(w, http.StatusCreated, task)
}

func (s *TaskStore) getTask(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	task, ok := s.tasks[id]
	if !ok {
		writeError(w, http.StatusNotFound, "Tarea no encontrada")
		return
	}
	writeJSON(w, http.StatusOK, task)
}

func (s *TaskStore) updateTask(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	task, ok := s.tasks[id]
	if !ok {
		writeError(w, http.StatusNotFound, "Tarea no encontrada")
		return
	}

	var req struct {
		Title       *string `json:"title"`
		Description *string `json:"description"`
		Completed   *bool   `json:"completed"`
	}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		writeError(w, http.StatusBadRequest, "Cuerpo de solicitud invalido")
		return
	}

	if req.Title != nil { task.Title = *req.Title }
	if req.Description != nil { task.Description = *req.Description }
	if req.Completed != nil { task.Completed = *req.Completed }

	writeJSON(w, http.StatusOK, task)
}

func (s *TaskStore) deleteTask(w http.ResponseWriter, r *http.Request) {
	id := chi.URLParam(r, "id")
	if _, ok := s.tasks[id]; !ok {
		writeError(w, http.StatusNotFound, "Tarea no encontrada")
		return
	}
	delete(s.tasks, id)
	w.WriteHeader(http.StatusNoContent)
}

func writeJSON(w http.ResponseWriter, status int, data interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(data)
}

func writeError(w http.ResponseWriter, status int, message string) {
	writeJSON(w, status, map[string]string{"error": message})
}

func requestLogger(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
		next.ServeHTTP(ww, r)

		slog.Info("Solicitud",
			"method", r.Method,
			"path", r.URL.Path,
			"status", ww.Status(),
			"duration_ms", time.Since(start).Milliseconds(),
			"request_id", middleware.GetReqID(r.Context()),
		)
	})
}

Patrones de procesamiento concurrente

> Crea una funcion que llame a multiples APIs concurrentemente y agregue los resultados.
> Implementa tambien cancelacion por contexto y timeout.
// concurrent.go
package service

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type AggregatedData struct {
	Users    []User    `json:"users"`
	Products []Product `json:"products"`
	Orders   []Order   `json:"orders"`
}

func FetchDashboardData(ctx context.Context) (*AggregatedData, error) {
	ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
	defer cancel()

	var (
		result AggregatedData
		mu     sync.Mutex
		wg     sync.WaitGroup
		errs   []error
	)

	// Obtener usuarios
	wg.Add(1)
	go func() {
		defer wg.Done()
		users, err := fetchUsers(ctx)
		mu.Lock()
		defer mu.Unlock()
		if err != nil {
			errs = append(errs, fmt.Errorf("obtener usuarios: %w", err))
			return
		}
		result.Users = users
	}()

	// Obtener productos
	wg.Add(1)
	go func() {
		defer wg.Done()
		products, err := fetchProducts(ctx)
		mu.Lock()
		defer mu.Unlock()
		if err != nil {
			errs = append(errs, fmt.Errorf("obtener productos: %w", err))
			return
		}
		result.Products = products
	}()

	// Obtener pedidos
	wg.Add(1)
	go func() {
		defer wg.Done()
		orders, err := fetchOrders(ctx)
		mu.Lock()
		defer mu.Unlock()
		if err != nil {
			errs = append(errs, fmt.Errorf("obtener pedidos: %w", err))
			return
		}
		result.Orders = orders
	}()

	wg.Wait()

	if len(errs) > 0 {
		return &result, fmt.Errorf("fallo parcial: %v", errs)
	}

	return &result, nil
}

Pruebas basadas en tablas

// main_test.go
package main

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestCreateTask(t *testing.T) {
	tests := []struct {
		name       string
		body       map[string]interface{}
		wantStatus int
	}{
		{
			name:       "tarea valida",
			body:       map[string]interface{}{"title": "Tarea de prueba"},
			wantStatus: http.StatusCreated,
		},
		{
			name:       "titulo vacio",
			body:       map[string]interface{}{"title": ""},
			wantStatus: http.StatusBadRequest,
		},
		{
			name:       "titulo faltante",
			body:       map[string]interface{}{},
			wantStatus: http.StatusBadRequest,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			store := NewTaskStore()
			body, _ := json.Marshal(tt.body)
			req := httptest.NewRequest(http.MethodPost, "/api/tasks", bytes.NewReader(body))
			req.Header.Set("Content-Type", "application/json")
			rec := httptest.NewRecorder()
			store.createTask(rec, req)
			if rec.Code != tt.wantStatus {
				t.Errorf("got status %d, want %d", rec.Code, tt.wantStatus)
			}
		})
	}
}

Resumen

Con Claude Code, puede desarrollar eficientemente Web APIs, procesamiento concurrente, herramientas CLI y pruebas en Go. Claude Code genera con precision los patrones idiomaticos de Go como manejo de errores y pruebas basadas en tablas. Para consejos basicos de eficiencia en desarrollo, consulte Tips para triplicar la productividad. Documentar las convenciones de Go en CLAUDE.md ayuda a mantener la consistencia.

Para mas detalles sobre Claude Code, consulte la documentacion oficial de Anthropic. Para la guia oficial de Go, consulte el sitio oficial de Go.

#Claude Code #Go #Golang #Web API #concurrencia