Saltar al contenido
Volver al blog
LaravelIABuenas prácticas

Tres errores que la IA repite en Laravel

Los asistentes de código escriben Laravel muy rápido, pero siempre tropiezan en las mismas tres piedras. Aprende a detectarlas antes de hacer merge.

Ismael Catala3 min de lectura

Llevo meses revisando pull requests escritas con ayuda de asistentes de código. El nivel medio ha subido muchísimo, pero hay tres errores que se repiten con una constancia sospechosa. Ninguno rompe la aplicación el día del merge: todos explotan tres meses después.

1. Consultas N+1 disfrazadas de código limpio

La IA adora los accessors. Le pides "muestra el nombre del autor de cada post" y te devuelve algo así:

class Post extends Model
{
    public function getAuthorNameAttribute(): string
    {
        return $this->user->name;
    }
}

Es legible, es correcto y es una bomba de relojería. En un listado de cincuenta posts acabas de disparar cincuenta y una consultas. El accessor esconde la relación, así que ni siquiera se ve al leer la vista.

La solución es la de siempre, pero hay que pedirla explícitamente:

Post::query()->with('user')->latest()->paginate(20);

Mi regla: cualquier accessor que toque una relación va acompañado de su $with o no entra. Si el modelo casi siempre necesita esa relación, decláralo en el propio modelo.

2. Validación en el controlador en lugar de en un Form Request

Cuando le pides un endpoint, la IA tiende a resolverlo todo en el método:

public function store(Request $request)
{
    $validated = $request->validate([
        'title' => 'required|string|max:255',
        'body' => 'required|string',
    ]);
 
    return Post::create($validated);
}

Funciona. El problema aparece cuando ese mismo recurso se crea también desde un comando de Artisan, desde un job y desde la API v2. Ahora tienes las reglas duplicadas en cuatro sitios y ya divergen.

Un FormRequest cuesta un php artisan make:request y te da validación, autorización y mensajes en un único punto:

class StorePostRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('create', Post::class);
    }
 
    public function rules(): array
    {
        return [
            'title' => ['required', 'string', 'max:255'],
            'body' => ['required', 'string'],
        ];
    }
}

Fíjate además en el detalle de las reglas como array en lugar de como string con pipes. No es cosmético: con reglas que contienen expresiones regulares o comas, la sintaxis de pipes se rompe de formas muy difíciles de depurar.

3. Ignorar las transacciones

Este es el más caro de los tres. Le pides "crea el pedido y descuenta el stock" y recibes dos operaciones seguidas, sin red de seguridad:

$order = Order::create($data);
$product->decrement('stock', $data['quantity']);

Si la segunda línea falla, te queda un pedido sin stock descontado. Nadie se entera hasta que alguien cuadra el inventario a fin de mes.

DB::transaction(function () use ($data, $product) {
    $order = Order::create($data);
    $product->decrement('stock', $data['quantity']);
 
    return $order;
});

Cómo lo abordo yo

No he dejado de usar asistentes: escribo más rápido y con menos fatiga. Lo que he cambiado es el sitio donde pongo la atención. Antes leía el código buscando errores de sintaxis; ahora leo buscando consultas escondidas, reglas duplicadas y escrituras sin transacción.

Y una cosa más: si le das contexto de tu proyecto al asistente —tus convenciones, tus modelos, tus repositorios— estos tres errores caen en picado. La IA no es mala escribiendo Laravel; es mala adivinando el Laravel que tú escribes.