Saltar al contenido principal

Cómo hago Code Review con IA sin perder criterio técnico: Workflow Humano + Claude Code

Autor
Ignacio AmatIgnacio Amat
Publicado
Lectura9 min
Interfaz de GitHub con comentarios automáticos de Claude Code y humanos

El Code Review es la práctica de mayor ROI para mantener un codebase sano, pero mal gestionado es el mayor cuello de botella. En 2026, mi flujo de revisión cambió radicalmente: IA para la mecánica, humano para la estrategia. Resultado: ciclo de feedback de días a horas, menos fatiga, código más robusto.


El Flujo Completo: 3 Fases, 0 Fricción

flowchart TD
    A[Dev abre PR] --> B[Claude Code: Filtro Automático]
    B --> C{¿Issues críticos?}
    C -->|Sí| D[Dev arregla + re-push]
    C -->|No| E[Reviewer Humano: 3 Pilares]
    E --> F[Aprobado + Merge]
    F --> G[Post-merge: Docs sync via MCP]

Fase 1: Filtro Automático — Claude Code (Pre-Review)

Antes de que yo abra el PR, el autor ejecuta (o CI ejecuta):

# En terminal del autor (o GitHub Action)
claude-code review \
  --base main \
  --head feature/nueva-feature \
  --prompt-file .claude/prompts/code-review.md \
  --output github-comments

Prompt Estándar (.claude/prompts/code-review.md)

# Code Review Automático — Proyecto: [Nombre]

## Contexto del Repositorio
- Stack: Laravel 11 + Vue 3 + Inertia + TypeScript + Pest
- Arquitectura: Modular Monolith (app/Modules/)
- Patrones: Action pattern, DTOs, Domain Events, Form Requests
- Testing: Pest (feature > unit), Vitest (components), Playwright (E2E crítico)
- Convenciones: PSR-12, Laravel Pint, TypeScript strict, Conventional Commits

## Qué Buscar (Prioridad Alta → Baja)

### 1. Seguridad (Crítico)
- Bypass de auth/autorización (Policy/Gate ausente)
- SQL Injection (DB::raw sin bindings, query builder inseguro)
- XSS (datos sin sanitizar en Blade/Vue)
- Exposición PII en logs, APIs, responses
- Pagos/auth/crypto: validación de entrada, idempotencia, PCI

### 2. Rendimiento (Alto)
- N+1 queries (falta `with()` / `loadMissing()`)
- Índices ausentes en migraciones (composite para queries multi-col)
- Jobs síncronos en request (email, PDF, webhook → cola)
- Cache misses evitables (config, traducciones, permisos)
- Sin batching en APIs externas (Stripe, ERPs)

### 3. Correctidad (Alto)
- Off-by-one, desreferencia null, race conditions
- Migraciones no reversibles en prod (`dropColumn` en SQLite test)
- Tests frágiles (dependen de orden, datos fijos, timers)
- Tipos: `any` en TS, `mixed` en PHP sin justificación

### 4. Arquitectura y Patrones (Medio)
- Lógica de negocio en Controller (→ Action/Service)
- DTOs tipados para props Inertia (TS interfaces = Laravel Resources)
- Eventos de dominio para desacoplamiento (no llamados directos cross-module)
- Form Requests para validación + autorización (no en Controller)

### 5. Mantenibilidad y Simplicidad (Medio)
- Funciones/clases > 1 responsabilidad (god classes)
- Duplicación lógica (DRY mal aplicado = acoplamiento)
- Nombrado: lenguaje ubicuo del dominio, no técnico genérico
- Complejidad ciclomática > 10 (refactor a funciones pequeñas)

### 6. Estilo y Convenciones (Bajo - IA maneja)
- PSR-12 / Laravel Pint
- TypeScript strict + ESLint
- Conventional Commits
- Imports ordenados, variables sin usar

## Formato de Salida
- Comentarios en GitHub (file:line) con severidad: 🔴 Crítico | 🟠 Alto | 🟡 Medio | 🔵 Bajo
- Sugerencia concreta de fix
- Referencia a patrón/ADR si aplica

Fase 2: Revisión Humana — Los 3 Pilares (Donde Gasto Mi Tiempo)

Una vez pasa el filtro auto (o autor arregla críticos), entro yo. Mi revisión se centra exclusivamente en lo que IA no domina:

Pilar 1: Intencionalidad de Negocio

Pregunta clave: “¿Este código resuelve el problema real del ticket, o solo el problema técnico que el dev asumió?”

## Ejemplo Real

Ticket: "Usuario puede cancelar suscripción mensual"

❌ PR implementa: Cancelación inmediata + reembolso automático
✅ Negocio requería: Cancelación al fin de período + prorrateo + email confirmación

Comentario PR:
> "Ticket LINEAR-1234 especifica 'cancelación al final del período actual con prorrateo'.
> Aquí cancela inmediata y reembolsa total.
> Confirmar con PO si comportamiento inmediato es intencional (cambio alcance) o bug.
> Si intencional, actualizar ticket y añadir test para prorrateo."

Pilar 2: Arquitectura y Escalabilidad (Vista a 6 Meses)

Pregunta clave: “¿Este cambio introduce acoplamiento que dolerá en 6 meses?”

// ❌ PR propone: Lógica facturación directo en Controller
class InvoiceController extends Controller {
    public function store(StoreInvoiceRequest $request) {
        $invoice = Invoice::create($request->validated());
        // Lógica negocio: 50 líneas cálculos, Stripe, ERP sync, emails
        $this->syncToERP($invoice);
        $this->sendConfirmationEmail($invoice);
        return $invoice;
    }
}

// ✅ Comentario Reviewer:
// "Esta lógica pertenece a `CreateInvoiceAction` (Action pattern).
// Controller solo: autoriza + valida + despacha Action + responde.
// Por qué? 1) Testable sin HTTP 2) Reutilizable CLI/Job/API 3) Separa concerns
// Ver app/Modules/Billing/Actions/CreateInvoiceAction.php para patrón existente."

Pilar 3: Mantenibilidad y Simplicidad

Pregunta clave: “¿El próximo dev (o yo en 6 meses) entenderá esto sin depurar?”

// ❌ PR propone: Helper "inteligente" con 15 params opcionales
function formatCurrency(
  amount: number,
  currency: string,
  locale?: string,
  showSymbol?: boolean,
  compact?: boolean,
  roundingMode?: 'ceil' | 'floor' | 'round',
  fallback?: string,
  // ... 8 más
): string { /* 80 líneas */ }

// ✅ Comentario Reviewer:
// "Esto es 'clever' pero frágil. Preferimos 2 funciones simples:
// 1) formatCurrency(amount, currency, locale?) → string (95% casos)
// 2) formatCurrencyCompact(amount, currency) → string (5% casos)
// Menos params = menos bugs, mejor autocomplete, testeable.
// DRY forzado aquí aumenta complejidad cognitiva, no la reduce."

Plantilla PR Obligatoria (.github/pull_request_template.md)

## 📋 Contexto
- **Ticket**: [LINEAR-XXXX](link) / [JIRA-XXXX](link)
- **Problema**: Qué resuelve este PR en una frase
- **Decisiones Clave**: ADR referenciado si aplica (ej. `docs/adr/014-stripe-webhook-idempotency.md`)

## 🧪 Testing
- [ ] Pest feature tests: happy path + edge cases (validación, auth, límites)
- [ ] Vitest component tests: props, events, states
- [ ] Playwright E2E: flujo crítico (si toca checkout, auth, pagos)
- [ ] Mutation testing (Infection): ≥ 80% en código nuevo
- [ ] Tests pasan en CI: `php artisan test --parallel` + `npm test`

## 🤖 Revisión IA (Pre-check)
- [ ] `claude-code review --base main` ejecutado localmente
- [ ] 🔴/🟠 issues resueltos antes de pedir revisión humana
- [ ] Commits atómicos, mensajes convencionales (`feat:`, `fix:`, `refactor:`)

## 👀 Para Reviewer Humano
- **Intencionalidad**: ¿Resuelve el ticket real?
- **Arquitectura**: ¿Encaja en `app/Modules/*/Actions|DTOs|Events`?
- **Simplicidad**: ¿Se lee sin depurar?
- **Nombrado**: Lenguaje ubicuo del dominio

## 🚀 Deploy
- [ ] Feature flag si cambio riesgoso (`config/feature-flags.php`)
- [ ] Migraciones reversibles (`down()` testeado)
- [ ] Runbook actualizado si nueva alerta/métrica

Métricas de Ciclo (Lo Que Medimos)

MétricaAntes (Solo Humano)Después (Humano + IA)Objetivo
Time to First Review18-48h2-4h< 4h
Ciclos de Review/PR3-51-2≤ 2
PR Cycle Time3-5 días4-12h< 24h
Comentarios “Nitpick”/PR8-151-3≤ 3
Bugs Prod/Release2-30-10
Fatiga Reviewer (encuesta)3.2/54.6/5≥ 4.5

Cultura: “IA para Mecánica, Humano para Estrategia”

Reglas de Equipo (En CONTRIBUTING.md)

  1. Autor ejecuta filtro IA ANTES de pedir revisión — “No me hagas perder tiempo en punto y coma”
  2. Reviewer humano SOLO comenta Pilares 1-3 — Si ves comentario de estilo, es fallo de proceso
  3. PRs pequeños (<300 líneas, 1 propósito) — Si no cabe, divídelo. IA revisa mejor PRs pequeños.
  4. SLA Revisión: 4h laborables — Si no puedes, reasigna. Botones “Approve/Request Changes” en GitHub.
  5. Post-merge: MCP sincroniza docs — ADRs, OpenAPI, CHANGELOG actualizados automáticamente vía MCP server.

Ejemplo de Comentario Humano “Bien Hecho”

> **Arquitectura** (Pilar 2)
> 
> En `app/Modules/Billing/Actions/CreateSubscriptionAction.php:45`
> 
> `SyncToERPJob` se despacha sincrónicamente dentro de la transacción BD.
> Si ERP falla → rollback suscripción → usuario sin suscripción pero Stripe cobró.
> 
> **Propuesta**: Mover `SyncToERPJob` fuera de transacción (after_commit) + compensación:
> ```php
> DB::transaction(function () {
>     $subscription = $this->createSubscription($data);
>     // Solo BD local aquí
> });
> 
> // After commit - si falla, compensar vía webhook Stripe + retry
> SyncToERPJob::dispatch($subscription)->afterCommit();
> ```
> 
> Ver `docs/adr/012-erp-sync-reliability.md` para patrón completo.
> 
> ¿Opiniones? Si acordado, implementar en este PR o ticket seguimiento.

Lo Que NUNCA Delego a IA (Lista Roja)

ÁreaPor Qué
Decisiones arquitectónicasIA optimiza local, pierde trade-offs sistémicos + negocio
Seguridad crítica (auth, pagos, crypto)Reviso línea a línea; IA asiste, no decide
Intencionalidad de negocioSolo humano valida contra ticket/PO/cliente
Merge finalApruebo diff completo en GitHub antes de merge
Nombrado dominioLenguaje ubicuo = acuerdo equipo, no sugerencia IA

Stack de Herramientas (2026)

HerramientaRol
Claude CodePre-review automático, refactoring, scaffolding tests
GitHub ActionsPuerta CI: tests, PHPStan, Pint, Lighthouse CI, Mutation testing
Sentry + PulseObservabilidad post-merge (error rate, perf, cron)
MCP ServersPost-merge doc sync (ADR, OpenAPI, CHANGELOG)
Linear/GitHub ProjectsTicket ↔ PR ↔ Deploy tracking

¿Quieres Implementar Esto en Tu Equipo?

Disponible para consultoría técnica (2-4 semanas) o contratación como Senior que trae este workflow listo.

Modalidades:

  • EOR (Deel, Remote, Oyster) — roles core indefinidos
  • Freelance B2B (Autónomo, factura intracomunitaria 0% IVA) — proyectos 3-12 meses
  • Indefinido directo — si tenéis entidad española

Stack: Laravel 11, PHP 8.3+, Vue 3 + TS, Inertia.js, Livewire 3, Astro, Docker, GitHub Actions, Laravel Pulse, Sentry, Claude Code / Cursor / MCP servers.

Ver Mi Perfil, Stack Completo y Condiciones →


Artículos Relacionados en Este Blog

Artículos relacionados

Revisa mi perfil como desarrollador

Si este artículo encaja con los retos técnicos de tu equipo, revisa mi stack o mi disponibilidad profesional.

Cuéntame qué necesitas

Puedes escribirme por un rol, contrato, colaboración técnica, una duda o una consulta general. Con 2-3 líneas de contexto suelo poder responder en menos de 24 horas hábiles.

0/500
Disponibilidad