La regla: si la instalación exige más de un comando, alguien lo hará mal, y la primera experiencia de esa persona con tu base de código será un mensaje de error que no tiene nada que ver con el producto.
# Bad: setup as a checklist someone copies into a wiki
$ php artisan serve # terminal one
$ php artisan queue:listen --tries=1 # terminal two, don't forget it
$ php artisan pail --timeout=0 # terminal three
Nadie recuerda todo eso el primer día, y para el día treinta cada persona recuerda un subconjunto distinto. Alguien olvida el worker de la cola y no entiende por qué DeleteLicenseJob no corre nunca. Cada uno de esos es un problema real con una causa falsa: no hicieron nada mal, el proceso les pidió recordar demasiado.
// composer.json
"scripts": {
"dev": [
"Composer\\Config::disableProcessTimeout",
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
]
}
composer run dev arranca el servidor, el worker de la cola, el visor de registros y la construcción del frontend juntos en una terminal, etiquetados para distinguirlos. Todo el camino de instalación son cuatro comandos, y cada uno es programable, lo que significa que cada uno es comprobable. Si alguien recién incorporado no consigue levantar la API, eso es un fallo en tu instalación, no una carencia suya.
Convenciones que se pueden deducir
Una convención sólo cuenta si quien llega puede adivinarla correctamente sin preguntar. Si tiene que preguntar, no es una convención: es un secreto.
BaseFormRequest es un ejemplo. Todas las clases de petición lo extienden, y el método abstracto rules() obliga a cada subclase a declarar sus reglas igual, con failedValidation() ya conectado a una respuesta de error estructurada. Quien ha leído un FormRequest los ha leído todos, porque la clase base no le deja divergir.
// tests/Feature/ArchTest.php
it('checks that my jobs have suffix Job')
->expect('App\Jobs')
->toHaveSuffix('Job');
Esta prueba no comprueba comportamiento. Comprueba forma. Cualquier clase en App\Jobs que no se llame AlgoJob hace fallar la construcción, sin ambigüedad sobre si es una preferencia o una regla.
El nombre te dice el contrato. Un sufijo Job significa ShouldQueue y ejecución asíncrona. La estructura te dice dónde vive la lógica. Los controladores se mantienen finos, las facades tienen la interfaz pública, los drivers el detalle específico del proveedor. Las pruebas te dicen qué está impuesto, no documentado. ArchTest.php no describe la convención: hace fallar la construcción cuando se rompe. Esa es la diferencia entre una convención y una sugerencia.