Código limpio: Argumentos

Código limpio: Argumentos

Cuando escribimos código debemos tener muy en cuenta además de los nombres y la calidad de nuestras funciones debemos preocuparnos por la calidad que tienen los argumentos de estas. En esta entrada vamos a ver algunas de las cosas que deberías tener en cuenta cuando estás definiendo tus argumentos. En esta entrega vamos a analizar el conocido filtro de twig localizeddate

Esta es la cuarta entrega de una serie en la que analizamos el libro clean code de Robert C Martin publicado en el año 2008. Si quieres pueder ir a ver el índice de la serie. También puedes ver la versión en video de esta entrada en nuestro canal de youtube.

Número de argumentos

Según el autor podríamos clasificar las funciones o los métodos según el número de argumentos posibles.

Monádicaos tienen un sólo argumento, son fáciles de testear y fáciles de entender. No hay lugar a dudas en cuanto a que es lo que hace y probablemente será bastante sencillo crear un test unitario para la misma. Siempre que podamos debemos basar nuestra api en este tipo de funciones.

Diádicos tienen dos argumentos. Siguen siendo relativamente fáciles de entender, y probablemente seguirán siendo fáciles de testear.

Triadicos son las que tienen tres argumentos, comienza a complicarse la forma de testear, aumenta la complejidad ciclomática o número de "caminos" posibles dentro de la función, y se complica recordar los argumentos y su orden. Este tipo de funciones deberían evitarse si es posible.

Cuatro o más argumentos Este tipo de funciones tienen todos los problemas que ya hemos comentado pero en mayor expotente. Veamos un ejemplo a continuación la función que ejecuta el filtro localizeddate de twig.

function twig_localized_date_filter(
    Twig_Environment $env,
    $date,
    $dateFormat = 'medium',
    $timeFormat = 'medium',
    $locale = null,
    $timezone = null,
    $format = null,
    $calendar = 'gregorian'
) {
    //..
}

Habitualmente usamos esta función de esta forma lo que la hace muy cómoda de usar

{{ item.date|localizeddate }}
{{ item.date|localizeddate('short', 'none') }} {# el uso de las constantes es muy cómodo en el día a día. #}

El problema viene cuando queremos pasarle un formato personalizado. Es muy dificil de recordar cuales son los argumentos, y tenemos que ir a la documentación para comprobarlo. Además los primeros dos argumentos son ignorados lo que la vuelve un poco confusa.

{{ item.date|localizeddate('none', 'none', null, null, 'MMMM y') }}
{{ item.date|localizeddate('full', 'full', null, null, 'MMMM y') }} {# ambas hacen lo mismo. #}

¿Que os parece si cambiamos esta función por dos? En la primera usaremos las constantes definidas para $dateFormat y $timeFormat mientras que en la segunda usaremos un formato personalizado.

function twig_localized_date_filter(
    Twig_Environment $env,
    $date,
    $dateFormat = 'medium',
    $timeFormat = 'medium',
    $locale = null,
    $timezone = null,
    $calendar = 'gregorian'
) {
//..
}

function twig_localized_date_filter_by_format(
    Twig_Environment $env,
    $date,
    $customFormat = null,
    $locale = null,
    $timezone = null,
    $calendar = 'gregorian'
) {
//..
}

Hemos reducido un poco el número de argumentos y hemos facilitado su utilización, ya que el uso de la segunda función quedaría en algo parecido a esto.

Nota: Aunque todavía son muchos argumentos el primero es injectado por twig asi que contaría uno menos.

{{ item.date|localizeddate('da_igual_lo_que_pongas', 'da_igual_lo_que_pongas', null, null, 'MMMM y') }} {# antes #}
  {{ item.date|localizeddate_by_format('MMMM y') }} {# mejor esta no? #}

Grupos de argumentos

En el caso en el que tenemos una función con un grupo de argumentos relacionados entre sí, podemos agruparlos todos ellos en una clase de forma que nuestro código mejora en su legibilidad. Es lo que han hecho aquí.

¿Que os parece si crearamos una clase para almacenar la configuración de la localización $locale, $timezone, $calendar. Es muy probable que este grupo de argumentos se repitan en otras funciones.

class Localization
{
    private $locale = null;
    private $timezone = null;
    private $calendar = 'gregorian';

    public function __construct($locale, $timezone, string $calendar)
    {
        $this->locale = $locale;
        $this->timezone = $timezone;
        $this->calendar = $calendar;
    }

}

Con esto mejoramos mucho la legibilidad del código, veamos cómo quedarían nuestras funciones anteriores

function twig_localized_date_filter(
    Twig_Environment $env,
    $date,
    $dateFormat = 'medium',
    $timeFormat = 'medium',
    $localization
) {
//..
}

function twig_localized_date_filter_by_format(
    Twig_Environment $env,
    $date,
    $customFormat = null,
    $localization
) {
//..
}

Orden de argumentos

A partir de este punto todo lo que vamos a ver no aparece en el libro, pero si que hemos querido completarlo con algunos criterios adicionales. Deberías tener en cuenta las siguientes condiciones a la hora de elegir el orden de los argumentos.

  • Los más importantes primero.
  • Utiliza el contexto para que el lector sepa cual es el primer argumento.
  • Trata de agrupar por tipos.
  • Argumentos opcionales al final.

Nombres

Los nombres de tus argumentos son parte de tu función. Trata de que séan lo más expecíficos posibles, ayuda al lector a entender tu función y lo que pueda esperar de ella, a través de esos nombres. ¿Que te parece este cambio?

function twig_localized_date_filter(
    Twig_Environment $env,
    $dateTime, // $date no era fiel a la realidad, ya que en ese argumento no importa sólo la fecha, si no también la hora.
    $dateFormat = 'medium',
    $timeFormat = 'medium',
    $localization
) {
//..
}

Tipado

El último apartado que me gustaría ver en esta entrada es el tipado. La regla es muy sencilla. Tipa siempre que puedas.

function twig_localized_date_filter(
    Twig_Environment $env,
    \DateTime $date,
    string $dateFormat = 'medium',
    string $timeFormat = 'medium',
    Localization $localization = null
) {
//..
}

function twig_localized_date_filter_by_format(
    Twig_Environment $env,
    \DateTime $date,
    string $customFormat,
    Localization $localization = null
) {
//..
}

El tipado también forma parte de tu función, quizá no tengas claro que es exactamente $localization, pero el tipado te ayuda a entender que se trata de una clase.

¿Quieres ser una bestia del desarrollo de software?
¡Continúa con nosotros en YouTube!

Todas las semanas un nuevo vídeo sobre desarrollo de software en tu bandeja de entrada.

Tranquilo, no te vamos a enviar spam.