Introducción
En el mundo de la IA generativa aplicada al desarrollo de software, constantemente aparecen nuevos modelos que prometen revolucionar nuestra forma de escribir código. Hoy pongo a prueba dos de los modelos más potentes del momento: GLM 4.7 (plan Max) de Zhipu AI y Claude Sonnet 4.5 de Anthropic.
El objetivo: refactorizar un controlador Laravel de 252 líneas aplicando buenas prácticas. Mismo prompt, mismo código base, resultados muy diferentes.
Nota: Si quieres aprender a usar GLM 4.7 con Claude Code, he publicado un curso donde explico cómo configurarlo paso a paso: Usa Claude Code sin cuenta de Anthropic con GLM
El Escenario de Prueba
Código Original
Un OrderController típico de Laravel con las siguientes características:
252 líneas de código
Lógica de negocio mezclada con validación
Estados de pedido como strings literales ("pendiente", "confirmado", etc.)
Código duplicado entre
store()yupdate()Sin separación de responsabilidades
Sin transacciones de base de datos
// Ejemplo del código original
public function store(Request $request)
{
$validated = $request->validate([
'customer_name' => 'required|string|max:255',
// ... validación inline
]);
try {
$orderNumber = 'ORD-' . date('Ymd') . '-' . Str::random(6);
$total = 0;
// ... lógica de negocio mezclada
$order = Order::create([...]);
// ... más lógica
} catch (\Exception $e) {
return back()->with('error', '...');
}
}El Prompt
Ambos modelos recibieron exactamente el mismo prompt:
Refactoriza este controlador de pedidos aplicando buenas prácticas Laravel:
Código limpio y mantenible
Separación de responsabilidades
Patrones apropiados para la lógica de negocio
No cambies la funcionalidad, solo mejora la arquitectura y calidad del código.
Resultados: GLM 4.7 Max
Ejecución Sin Errores
GLM 4.7 completó la refactorización sin ningún error. El código funcionó correctamente desde el primer intento.
Estructura Creada
app/
├── OrderStatus.php # Enum en raíz de app/
├── OrderQuery.php # Query class simple
├── Services/
│ └── OrderService.php # Service layer
└── Http/
└── Requests/
├── StoreOrderRequest.php
├── UpdateOrderRequest.php
└── UpdateOrderStatusRequest.phpDecisiones de Arquitectura
1. Enum de Estados
<?php
namespace App;
enum OrderStatus: string
{
case Pendiente = 'pendiente';
case Confirmado = 'confirmado';
case Enviado = 'enviado';
case Entregado = 'entregado';
case Cancelado = 'cancelado';
public function isNotEditable(): bool
{
return in_array($this, [self::Enviado, self::Entregado, self::Cancelado]);
}
public function isDeletable(): bool
{
return $this === self::Pendiente;
}
}2. Service Layer
Toda la lógica de negocio centralizada en OrderService:
public function createOrder(array $orderData, array $items): Order
{
return DB::transaction(function () use ($orderData, $items) {
$order = Order::create($orderData);
foreach ($items as $item) {
$order->items()->create($item);
}
return $order;
});
}3. Query Class Simple
class OrderQuery
{
public function applyFilters(array $filters): Builder
{
$query = Order::query();
// ... aplica filtros
return $query;
}
}4. Controlador Resultante (142 líneas)
class OrderController extends Controller
{
public function __construct(
private OrderService $orderService,
private OrderQuery $orderQuery
) {}
public function store(StoreOrderRequest $request): RedirectResponse
{
$validated = $request->validated();
['items' => $items, 'total' => $total] = $this->orderService->calculateOrderTotal($validated['products']);
$order = $this->orderService->createOrder($orderData, $items);
return redirect()->route('orders.show', $order)
->with('success', "Pedido creado correctamente");
}
}Lo Que NO Tocó
GLM 4.7 no modificó el modelo Order.php. Mantuvo la propiedad $casts original sin actualizarla al método casts() de Laravel moderno.
Resultados: Claude Sonnet 4.5
Ejecución Con Errores
Sonnet 4.5 produjo código que falló con 4 errores antes de funcionar correctamente:
Error en QueryBuilder:
Declaration of OrderQueryBuilder::latest()incompatible conIlluminate\Database\Eloquent\Builder::latest($column = null)Error en Vista: TypeError en
index.blade.php:77Error en UpdateOrderStatus:
OrderStatus::from()recibiendo unOrderStatusen lugar de stringError en UpdateOrderRequest: Mismo problema de tipos con el enum
Estructura Creada
app/
├── Actions/
│ ├── CreateOrder.php
│ ├── UpdateOrder.php
│ └── UpdateOrderStatus.php
├── Enums/
│ └── OrderStatus.php # Enum en carpeta dedicada
├── QueryBuilders/
│ └── OrderQueryBuilder.php # Custom Query Builder
└── Http/
└── Requests/
├── StoreOrderRequest.php
├── UpdateOrderRequest.php
└── UpdateOrderStatusRequest.phpDecisiones de Arquitectura
1. Enum con Método label()
<?php
namespace App\Enums;
enum OrderStatus: string
{
case Pendiente = 'pendiente';
// ...
public function label(): string
{
return match ($this) {
self::Pendiente => 'Pendiente',
// ...
};
}
public function isEditable(): bool
{
return match ($this) {
self::Pendiente, self::Confirmado => true,
default => false,
};
}
}2. Patrón Action
En lugar de un Service, usó Actions individuales:
class CreateOrder
{
public function execute(array $data, int $userId = 1): Order
{
$orderNumber = $this->generateOrderNumber();
$items = $this->prepareOrderItems($data['products']);
$total = $this->calculateTotal($items);
$order = Order::create([...]);
$this->createOrderItems($order, $items);
return $order->fresh('items.product');
}
}3. Custom Query Builder Integrado al Modelo
// En Order.php
public function newEloquentBuilder($query): OrderQueryBuilder
{
return new OrderQueryBuilder($query);
}
// Permite llamadas como:
Order::query()->applyFilters($request)->latest()->paginate(15);4. Modelo Actualizado a Laravel Moderno
class Order extends Model
{
public function casts(): array // Método en lugar de propiedad
{
return [
'status' => OrderStatus::class, // Cast automático al Enum
'total' => 'decimal:2',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
}
public function isEditable(): bool
{
return $this->status->isEditable();
}
public function isDeletable(): bool
{
return $this->status->isDeletable();
}
}5. Controlador Resultante (129 líneas)
public function store(StoreOrderRequest $request, CreateOrder $createOrder): RedirectResponse
{
try {
$order = $createOrder->execute($request->validated());
return redirect()->route('orders.show', $order)
->with('success', "Pedido creado correctamente: {$order->order_number}");
} catch (\Exception $e) {
return back()->with('error', '...')->withInput();
}
}Origen de los Errores
Los 4 errores de Sonnet 4.5 tienen una causa común: inconsistencia entre el cast automático del enum y el código que esperaba strings.
Al configurar 'status' => OrderStatus::class en el modelo, $order->status ya es un OrderStatus, no un string. Pero en varios lugares, el código intentaba:
// Error: $order->status ya es OrderStatus, no string
OrderStatus::from($order->status)
// Error: ucfirst espera string, recibe OrderStatus
ucfirst($order->status)Este tipo de error revela una falta de coherencia interna en el refactor. El modelo se actualizó correctamente, pero el resto del código no se adaptó de forma consistente.
Comparativa Directa
Aspecto | GLM 4.7 Max | Claude Sonnet 4.5 |
|---|---|---|
Errores iniciales | 0 | 4 |
Funcionó a la primera | Sí | No |
Líneas controlador | 142 | 129 |
Archivos nuevos | 5 | 7 |
Patrón principal | Service Layer | Actions |
Ubicación Enum |
|
|
Query Builder | Clase standalone | Integrado al modelo |
Modificó Model | No | Sí |
Usa casts() | No (mantiene $casts) | Sí |
Cast del status | Manual (string) | Automático (Enum) |
Transacciones DB | Sí | No |
Documentación | Básica | Exhaustiva |
Análisis Técnico
Ventajas de GLM 4.7
Fiabilidad: Código funcional sin iteraciones de corrección
Transacciones: Uso correcto de
DB::transaction()para operaciones atómicasConservador: No tocó lo que no era necesario (el modelo funcionaba)
Pragmático: Estructura simple y directa
Ventajas de Sonnet 4.5
Modernización: Usó
casts()en lugar de$casts(Laravel moderno)Cast automático: El enum se castea automáticamente en el modelo
Organización: Estructura de carpetas más limpia (
Enums/,Actions/,QueryBuilders/)Query Builder integrado: Patrón más elegante para queries
Método label(): El enum puede mostrar su representación visual
Helpers en modelo:
$order->isEditable()es más expresivo que$this->orderService->canEditOrder($order)Documentación: REFACTOR.md mucho más detallado
La Paradoja de Sonnet 4.5
Sonnet 4.5 tomó decisiones arquitectónicamente más correctas:
El cast automático del enum es la forma idiomática de Laravel 11+
casts()es el estándar actualEl Query Builder integrado al modelo es más elegante
Pero falló en la coherencia interna. Al hacer el cambio al cast automático, no adaptó consistentemente todo el código que dependía del tipo de $order->status.
Esto sugiere que Sonnet 4.5 tiene un conocimiento más profundo de las mejores prácticas modernas de Laravel, pero carece de la atención al detalle necesaria para implementarlas sin errores.
La Solidez de GLM 4.7
GLM 4.7 optó por un enfoque más conservador:
No modificó el modelo
El enum no se castea automáticamente
Se usa
OrderStatus::from($order->status)explícitamente donde hace falta
Este enfoque es menos elegante pero 100% funcional. No hay posibilidad de error por inconsistencia de tipos porque el tipo siempre es predecible.
Las Transacciones: Un Punto Crítico
Un detalle que no debe pasar desapercibido: GLM 4.7 implementó transacciones de base de datos y Sonnet 4.5 no.
// GLM 4.7 - OrderService.php
public function createOrder(array $orderData, array $items): Order
{
return DB::transaction(function () use ($orderData, $items) {
$order = Order::create($orderData);
foreach ($items as $item) {
$order->items()->create($item);
}
return $order;
});
}// Sonnet 4.5 - CreateOrder.php
public function execute(array $data, int $userId = 1): Order
{
$order = Order::create([...]);
$this->createOrderItems($order, $items); // Sin transacción
return $order->fresh('items.product');
}Si la creación de items falla, con GLM 4.7 se hace rollback completo. Con Sonnet 4.5, quedaría un pedido huérfano sin items. En producción, esto es un bug crítico.
Conclusión
El Veredicto
GLM 4.7 Max gana esta comparativa, no por elegancia técnica, sino por lo que más importa en el mundo real: código que funciona a la primera.
En un entorno de desarrollo real:
GLM 4.7 habría permitido continuar trabajando inmediatamente
Sonnet 4.5 habría requerido debugging y 4 correcciones manuales
¿Cuándo Elegir Cada Uno?
Elige GLM 4.7 si:
Necesitas código funcional rápidamente
Valoras la fiabilidad sobre la elegancia
Trabajas en producción donde los errores tienen costo
Prefieres un enfoque conservador
Elige Sonnet 4.5 si:
Tienes tiempo para revisar y corregir
Quieres aprender mejores prácticas modernas
Valoras la documentación exhaustiva
Planeas usar el código como base educativa
Reflexión Final
Esta comparativa ilustra una verdad incómoda sobre los modelos de IA: conocimiento no es lo mismo que ejecución. Sonnet 4.5 demostró conocer patrones más modernos y mejores prácticas, pero falló en la implementación coherente.
GLM 4.7, con un enfoque más conservador, entregó código funcional sin sorpresas. En el desarrollo de software, a veces "boring" es exactamente lo que necesitas.
El código de ambos modelos está disponible en las ramas glm47 y sonnet45 del repositorio para que puedas analizarlo tú mismo.
Próximamente: ¿Claude Opus 4.5?
En una futura comparativa, pondremos a prueba a Claude Opus 4.5, el modelo más potente de Anthropic. Será interesante ver si el hermano mayor de Sonnet logra combinar el conocimiento técnico avanzado con la fiabilidad que demostró GLM 4.7.
Prueba realizada el 26 de diciembre de 2025 usando GLM 4.7 (plan Max) y Claude Sonnet 4.5 sobre un proyecto Laravel con un sistema de gestión de pedidos.
¿Quieres usar GLM 4.7 con Claude Code? Aprende cómo configurarlo en mi curso: Usa Claude Code sin cuenta de Anthropic con GLM
Artículos relacionados
GLM 4.7: La IA China que Compite con los Grandes por una Fracción del Precio
Desarrollo con IA Económico: Kilo Code + GLM-4.6 para Laravel
Curso Laravel 12
Completo 2026
El único curso 100% actualizado que incluye Laravel 12, Livewire 3, Vue 3, React 19 e Inertia 2. Aprende con proyectos reales y las últimas funcionalidades.
star Incluido en cualquier suscripción