La popularidad de Laravel no deja de crecer y la aparición de consultoras que trabajen exclusivamente con este framework es prueba de ello. Siendo un framework que utilizamos en proyectos de gran envergadura, es importante conocer practicas que nos permitirán mantener la deuda técnica de nuestro código a raya y hacerlo lo más mantenible posible. En este articulo mencionare 10 tips, que a mi parecer, son indispensables a la hora de mantener un proyecto con Laravel.

1.- Mantén tus controladores y modelos a dieta

Cuando Rails comenzó a ganar popularidad, uno de los primeros problemas a los que se enfrento la comunidad fueron los controladores de miles de lineas llenas de lógica de negocios. Los modelos eran la representación de la lógica de negocio, y por lo mismo, se propuso que la lógica de negocios debía vivir en ellos. Como era de esperar, los modelos pasaron a ser quienes tenían miles de lineas de código y el problema se repitió.

La complejidad de tu código debe vivir en algún lado, no existe forma en la que nos podamos deshacernos de ella, lo que si podemos hacer, es ponerla en el lugar correcto, ese lugar no son los controladores ni tus modelos. Entonces, ¿cual es?, como todos dicen, depende de tus necesidades.

Laravel te permite crear nuevas carpetas en tu proyecto y establecer tus propios patrones. Quiero Mi Switch es un proyecto que desarrolle hace un tiempo, el cual visita distintos sitio de e-commerce revisar los precios de cierto producto, había mucho código destinado a rastrear e indexar estos sitios, mi decisión fue crear una carpeta app/Crawlers donde se encuentra la lógica relacionada a obtener información de los distintos sitios.

Si en algún momento tienes código que no creas que deban ir en un servicio, quizas la solución es crear una carpeta nueva para algún patron que si te haga sentido.

2.- Despidete de los array methods y utiliza las colecciones de Laravel

Mis años escribiendo código en PHP mejoraron instantáneamente una vez que descubrí las colecciones de Laravel. Los métodos de PHP hacen imposible la tarea de escribir código legible:

array_reduce(
   array_map(
      function($num) { return $num * 2; },
      [1, 2, 3]
   ),
   function($carry, $num) { return $carry + $num; }
 );

En cambio, re-escribir este mismo trozo de código usando collectiones es mucho más intuitivo y simple de leer:

 collect([1, 2, 3])
  ->map(function($num) { return $num * 2; })
  ->reduce(function($carry, $num) { return $carry + $num; })

Los beneficios de escribir código utilizando este estilo sobre los loops son infinitos, incluso podríamos crear custom collections para mejorar aún más la legibilidad de este ejemplo. Si pudiera pedir un deseo, sería que las collections fueran nativas en PHP.

3.- Diseña tus vistas utilizando Componentes

En Laravel 5.4, Blade incluyo la posibilidad de crear tus propios componentes, en ese entonces estos componentes solo eran una etiqueta, la cual podía usar slots (similar a los props en Vue y React). Si bien es una feature muy potente (y no, no es reemplazable por partials ni por sub-views), algo faltaba, seria genial poder encapsular las responsabilidades de este componente y declarar sus dependencias, pronto aparecieron paquetes que nos permitieran lograr esto, pero con Laravel 7, el diseño basado en componentes se volvió una realidad en el mismo framework.

Si utilizas Vue o React para el frontend de tu aplicación, este consejo no es de gran utilidad, pero si aún usas Blade, utilizar componentes es, a mi parecer, casi obligatorio. Los beneficios son similares a los que vemos al usar frameworks de frontend, solo que sin las interacciones de javascript, con los componentes nos podemos olvidar de escribir HTML de nuestros componentes tantas veces, podemos encapsular la lógica de ellos en una clase y así evitar los archivos helpers que ensucian el scope global con métodos que solo utilizara una vista, etc.

4.- Restringe tu código con Linters

La comunidad de PHP ha llegado a muchos acuerdos y ha diseñado muchas herramientas que nos obligan a seguir esos acuerdos. ¿Porqué esto es útil?, nos permiten forzar la consistencia de nuestro código, esto es extremadamente útil cuando tenemos un equipo grande de gente o cuando llegan nuevos desarrolladores, todos sabemos que no basta con una guia de desarrollo explicando las reglas, eventualmente perderemos tiempo apuntando estos errores en los Pull Requests. Los linters que ha armado la comunidad nos permite delegar este trabajo.

  • PSR-1 y PSR-2 definen guías de estilos para nuestro código. Existen otras, pero herramientas como PHP-CS-Fixer te permiten revisar si tu código cumple con alguno de estos dos estándares o definir reglas extras sobre ellos.
  • PHPStan es un analizador estático que encuentra bugs comunes en nuestro código.
  • PHPLoc nos retorna distintas métricas sobre nuestro código, como la complejidad ciclomatica y las clases/métodos más largos. Me gusta definir limites en el tamaño de mis clases y métodos, y PHPLoc me permite obtener esta estadística y hacerla parte del proceso de revisión automático de cada Pull Request.

5.- Los jobs, comandos y controladores solo son puntos de entrada

Supongamos que tienes un pedazo de código que actualiza diversas variables en tu base de datos. En ocaciones necesitamos que el usuario pueda gatillar está acción desde un controlador, pero tambien, que está acción se realice de forma automática cada cierto tiempo. En otras palabras, se ejecuta el mismo código en un controlador y en un job.

Aquí queda claro lo importante que es mantener la lógica de negocio fuera de los controladores, pero lo mismo tambien es valido para los jobs y comandos. Los controladores, jobs y comandos de artisan solo son puntos de entrada de nuestra aplicación y su único trabajo es conectar un punto de entrada en particular, con nuestra lógica de negocio.

¿Necesitas ejecutar una acción por medio de una url?, un controlador sabe como recibir una Request y ejecutar un servicio. ¿Necesitas ejecutar esa acción de forma diaria?, un job se ejecutara de forma diaria (gracias a algún scheduler) para ejecutar tu servicio, ¿necesitas ejecutar una acción por la terminal?, entonces creas un comando que te permite llamar al servicio por medio del CLI.

6.- No ejecutes queries en las vistas

Las vistas tienen dos responsabilidades: presentar tus datos y ser lo más tontas posibles. Un modelos de Eloquent haciendo queries en un template de Blade es una alerta que no debemos pasar por alto.

A veces puede ser tentador llamar a un modelo desde la vista, pero caer en ese desorden nos invisibiliza las dependencias de las vistas, les otorga trabajo extra que sera difícil de refactorizar y además, podríamos tener, a futuro, problemas de performances por queries que se ejecutan en lugares difíciles de encontrar.

7.- La optimización prematura es la fuente de todos los males

No hay nada de malo en sacrificar performance por legibilidad. Si tu aplicación comienza a tener más clientes y tus servidores no son capaces de manejar todas las peticiones que llegan, te aseguro que tienes un problema del cual deberías estar bastante contento.

Laravel nos facilita la vida a la hora de escalar horizontalmente, cada una de sus piezas puede ser reemplazada fácilmente, ¿Necesitas usar Redis para mantener las sesiones independientes de la maquina que ejecuta el código?, basta con cambiar un par de configuraciones y se conectara con Redis. Así que no te preocupes, Laravel nos permite despreocuparnos un poco de la performance en favor de ser más ágil.

8.- Puedes extender el framework usando macros

De seguro más de alguno desearía poder definir las llaves foraneas en una sola linea:

Schema::table('users', function (Blueprint $table) {
   $table->createForeign('company');
});

Lamentablemente PHP no nos facilita las cosas a la hora de querer extender el framework (a diferencia de otros lenguajes como Ruby), pero Laravel nos regalo el trait macroable, este trait nos permite extender las clases internas del framework para incluir cualquier caso de uso particular que tengamos.

De esta forma podemos definir un macro que nos permita crear llaves foraneas en una sola linea:

Blueprint::macro('createForeign', function($model) {
    $column = "{$model}_id";
    $table = Str::snake(Str::pluralStudly($model));
    $this->unsignedBigInteger($column);
    $this->foreign($column)->references('id')->on($table);
});

9.- Tinker y php -a son tus mejores amigos

Infinidad de veces he visto a programadores creando una ruta para probar un trozo de código. Esto no es necesario, abre una terminal y escribe php artisan tinker en el directorio de tu proyecto, instantáneamente tendrás una consola interactiva de PHP con el framework listo para ser usado donde incluso puedes llamar a los modelos de Eloquent \App\User::first() para realizar queries a tu base de datos.

Lo mismo es valido con php -a, quien te permite acceder a una consola interactiva de PHP.

Tinker es un wraper sobre PsySh una consola de PHP con superpoderes que nos permite revisar el historial de comandos que hemos ejecutado, autocompletar código con tab y muchas otras features que podemos revisar en la documentación de PsySh

10.- No existen las balas de plata

Si bien estos consejos o cualquier otro que leas en internet, pueden ser muy útiles, ninguna regla debe ser tallada en piedra. Cualquiera que haya visto la evolución de Laravel (o cualquier otro framework/lenguaje/libreria), se habra dado cuenta de como hoy en día tenemos características que hace un par de años eran consideradas innecesarias por los mismos miembros de la comunidad, pero con las cuales, de seguro no podríamos vivir.

Espero que este articulo ayuden a mejorar tu día a día, si tienes alguna otra recomendación me la puedes hacer llegar por twitter.