domingo, 13 de noviembre de 2016

Factory Method. Parte III - Variante en PHP (u otros lenguajes)

Después de ver el caso más tradicional del patrón factory method, donde cada producto concreto tenía que tener una subclase del creador asociada, vamos a ver una variante para aplicar con lenguajes como PHP.

El principal problema del factory method reside en que, si tenemos muchos subproductos, vamos a tener una gran cantidad de subclases constructoras de esos productos, además de que la clase cliente debe heredar de la clase creadora; vamos a crear una jerarquía de clases como clase padre el creador que puede tener subclases muy similares entre sí.

En el anterior caso de la clase para crear una habitación, para diferenciarlo del caso que veremos a continuación, teníamos dos tipos de subproductos en cada subclase creadora: sillas y proyector. Lo más normal es que para aplicar el factory method tengamos sólo 1 tipo de producto, ya que si hay varios tipos de producto que deben trabajar siempre de forma conjunta el patrón evolucionará a un abstract factory pattern.

Así que, para comenzar, vamos a mostrar un ejemplo muy simple en el que el cliente usa un método creador para obtener distintos tipos de notificadores (email y sftp).
[code] $data = array( 1,2,3,4,5 ); $typeNotifications = array( Notifier::EMAIL, Notifier::SFTP, Notifier::EMAIL ); foreach ($typeNotifications as $type) { $notifier = Notifier::getNotifier( $type, $data ); echo( $notifier->notify() . PHP_EOL ); } [/code]
El ejemplo es muy simple, pero para imaginar un caso más real las variable $data y $typeNotifications podrían ser objetos con toda la información, o registros de una base de datos, o lectura de un fichero, ..., pero vamos a simplificarlo para ver con más claridad qué ocurre:

Detalles que llaman la atención:
  • El método creador es un método estático de la clase Notifier, es decir, no hay clase creadora.
  • Al método creador se le pasan parámetros.
  • En el ejemplo vemos que hay 3 tipos de notificaciones: email, sftp y otra vez email.

Tras ejecutar ese código tenemos el siguiente resultado:
[code] Notifyied by email next data: 1,2,3,4,5 Notifyied by sftp next data: 1,2,3,4,5 Notifyied by email next data: 1,2,3,4,5 [Finished in 0.1s] [/code]
Se observa que hemos obtenido en total dos notificadores tipo email y uno tipo sftp, tal como hemos indicado en la variable $typeNotifications. El polimorfismo entra en acción.

Entonces, ¿Dónde está la clase creadora concreta que nos devuelve el producto concreto que tiene asociado? No hay.

Veamos la clase Notifier:
[code] abstract class Notifier { const EMAIL = "email"; const SFTP = "sftp"; protected $data = array(); final private function __construct( array $data ) { $this->data = $data; } public static function getNotifier( string $type, array $data ) : Notifier { switch ( trim( $type ) ) { case self::EMAIL: return new EMailNotifier($data); break; case self::SFTP: return new SftpNotifier($data); break; default: throw new \Exception("Error: Notifier ".$type." is not available"); break; } } public abstract function notify() : string; } [/code]
Vamos a ver los puntos más importantes de esta clase:
  • Es una clase abstracta, por tanto no puede ser instaciada: no habrá objetos de la clase Notifier.
  • El método getNotifier() es estático, se puede llamar sin tener un objeto de la clase. Este es el método creador que, como se ve, devuelve una clase concreta de Notifier.
  • El constructor es privado. De esta forma una clase cliente sólo puede obtener un tipo Notifier a través del método creador.
  • El constructor es final. Con esto evitamos que las subclases puedan sobrescribir el constructor. Volvemos a reforzar que las subclases sólo se puedan obtener a través del método creador.

Los más destacado es ver que el método creador se ha movido a la clase abstracta del producto.

Con esto ya sólo necesitamos las subclases de Notifier.

Clase EmailNotifier:
[code] class EmailNotifier extends Notifier { /** * Notify */ public function notify() : string { return "Notifyied by email next data: ".implode(",", $this->data); } } [/code]
Clase SftpNotifier:
[code] class SftpNotifier extends Notifier { /** * Notify */ public function notify() : string { return "Notifyied by sftp next data: ".implode(",", $this->data); } } [/code]
Con esta variante del patrón factory method no es necesario crear una estructura jerárquica de creadores ni necesitamos que nuestra clase cliente herede de la clase creadora.

El factory method pattern, tal y como lo vemos en este ejemplo, gana mucho aplicándolo junto a principios SOLID como la inyección de dependencias.

El código de github aquí.

sábado, 5 de noviembre de 2016

Factory Method. Parte II - Ejemplo

Tras el post sobre la importancia de sacar la creación de clases concretas de nuestro sistema toca mostrar algunos ejemplos.

Voy a comenzar por el caso más tradicional, que es sobre el que más hincapié se hace en el libro Design Patterns: Elements of reusable object-oriented software. He estado pensando qué ejemplo poner, ya que en dicho libro vienen 2, uno muy genérico sobre una aplicación y la creación de tipos de documentos, y otro más amplio escrito en C++ sobre la generación de laberintos para un juego. He elegido crear un caso intermedio entre ambos, pero recomiendo leer los ejemplos del libro.

Caso: Tenemos un emulador de realidad virtual que en un momento dado crea una habitación de entretenimiento. El sistema debe ser capaz de elegir entre una habitación para ver videos y otra para escuchar audio. Para que podamos centrarnos en el patrón de diseño he creado clases muy simples.

Implementación de Factory Method: Esto es importante entenderlo para comprender el origen de la motivación del patrón. La propia aplicación, es decir, la clase que representa la habitación (EntertaimentRoom), es la que tiene los métodos creadores y los llama ella misma junto con otros métodos.

Lo primero de todo analicemos la clase EntertaimentRoom antes de aplicar Factory Method. Aquí todo el código.


Vemos las siguientes características:
  • Tiene un método begin() que hace que comience la actividad de la habitación.
  • Hay un método llamado begin_old, con un único condicional, que hace más de una cosa, por lo que se ha refactorizado en métodos individuales.
  • Por desgracia cada método individual contiene el condicional, es un bad smell de libro.
  • La clase está llena de llamadas a constructores de clases concretas, lo que hace que el código central esté acoplado a la creación de subclases.
  • El constructor recibe el tipo de habitación que se debe crear.

En la clase Main vemos cómo se instancia y cómo se usa un objeto EntertaimentRoom. Vemos que añadir o eliminar una subclase requiere tocar mucho el código central, y eso que está muy simplificado.
[code] $room = new EntertaimentRoom(EntertaimentRoom::VIDEO); $room->begin(); [/code]
En este punto decidimos aplicar el patrón Factory Method.

Aquí todo el código.

La idea principal es que cada subclase de la clase creadora decida qué objetos debe utilizar. Como hemos dicho antes la clase EntertaimentRoom es la que genera las clases concretas, por lo tanto es la que llama a los métodos de creación; es la clase creadora.

La clase EntertaimentRoom tendrá subclases que sobrescriben los métodos creadores. EntertaimentRoom nunca sabrá qué clases concretas hay que crear, ese conocimiento estará en sus clases hijas.

Hacemos que EntertaimentRoom sea ahora una clase abstracta con las siguientes características:
  • Los métodos createPlayer(), getStartInstructions() y createChairs() son ahora abstractos. Se implementan en cada subclase.
  • El constructor ya no necesita recibir el tipo de la habitación, ya que no hay ningún condicional. Desaparece la variable de clase $type.
  • Creamos las clases AudioEntertaimentRoom y VideoEntertaimentRoom como subclases de la clase creadora.
  • En el fichero Main hacemos un cambio aprovechando las características de PhP. En un fichero json metemos el tipo de habitación, pero podría leerse de base de datos, generarse forma aleatoria o ser introducido por el usuario.

Este sería el nuevo fichero Main:
[code] $dataFile = file_get_contents(__DIR__."\config.json"); $roomConfig = json_decode($dataFile); $strClassRoom = "blog\\factory\\rooms\\".ucfirst(strtolower($roomConfig->type))."EntertaimentRoom"; $room = new $strClassRoom(); $room->prepareChairs(); $room->begin(); [/code]
Y este el json:
[code]{"type":"audio"}[/code]
Con ese JSON el fichero Main.php genera una clase AudioEntertaimentRoom que crea, gracias a los métodos de creación, objetos Player y Chair apropiados para ese tipo de habitación. Cambiando el json podríamos crear una habitación de tipo VideoEntertaimentRoom.

Ahora para añadir una nueva habitación sólo tendríamos que construir una nueva subclase de EntertaimentRoom y subclases Player y Chairs.

En versiones anteriores de PhP tenemos el problema de que no sabemos qué devuelve cada clase abstracta, por lo que habría que mirar qué puede devolver cada subclase, pero en PhP7 podemos tipar los retornos, incluso poner tipado estricto, y con ver las interfaces ya sabríamos qué debe devolver cada método. No haría falta ni tocar el código central ni mirar otras subclases.

Esta implementación tiene las siguientes características.

La clase cliente es la que tiene los métodos creadores, ella misma los usa, por lo tanto la clase cliente hereda de la clase creadora. Con la implementación realizada tendríamos una subclase de creador por cada tipo de producto.

Si la clase creadora sólo generase un subtipo de Producto podríamos no necesitar crear subclases de la clase creadora. La clase creadora sería concreta y podría incluir un método creador parametrizado que devolvería el tipo de producto.

El ejemplo realizado tiene otra variante: la clase EntertaimentRoom no es abstracta e implementa los métodos creadores. Las subclases del creador, de necesitarse, podrían sobrescribir parte del método creador de la clase padre; por ejemplo si hay dos habitaciones con el mismo objeto Player pero distinto objeto Chairs. Incluso aplicando propiedades del lenguaje utilizado, y pasando un parámetro, podríamos evitar tener una clase creadora (se verá en otro post).

Y para finalizar, ¿Qué ocurre si EntertaimentRoom ya hereda de Room? ¿Y si hay muchos objetos productos? ¿Y si para aplicar Factory Method tenemos que forzar que el cliente herede de la clase creadora? No es recomendable ya que estamos condicionando el futuro. Todas estas preguntas nos llevan a evolucionar de Factory Method a Abstract Factory Pattern, el cual puede utilizar Factory Methods como base, pero esa es otra historia que dejaremos para otro día.

Código sin Factory Method aquí.
Código con Factory Method aquí.
Código con variante de Factory Method aquí.

jueves, 20 de octubre de 2016

Factory Method. Parte I - Introducción

Una norma básica para evitar acoplamiento entre clases concretas y el cliente que las usa es trabajar para la interface y no para la implementación. De eso se trata: no queremos clases concretas en nuestro código.

Tenemos nuestro código, con la lógica de negocio, que utiliza distintas clases que heredan de una interface común, pero, ¿cómo hacemos para no utilizarlas directamente? Esa es la gran incógnita a resolver.

¿Por qué no queremos clases concretas en nuestro código?


Imaginemos los siguientes casos:

  • Tenemos código que queremos reutilizar en distintos proyectos ya que la parte central hace algo concreto, pero en cada proyecto, por lo que sea, ese algo concreto se hace de distintas formas. 
  •  Queremos que nuestro código central no tenga que ocuparse de cosas que no son su cometido. Dicho de otra forma, tenemos código central que para lograr su fin puede utilizar distintos caminos que no tenemos porqué conocer, queremos que el sistema sea independiente de sus productos.

En ambos casos aprovechamos clases concretas de un mismo tipo. Utilizamos polimorfismo. En estos casos la clase principal no puede saber qué productos debe crear.

Esas clases concretas se pueden seleccionar en un largo condicional dentro del código central, y eso es precisamente lo que queremos evitar. Y además, para el condicional necesitaríamos un parámetro en el código central que no haría falta para nada más.

¿Qué pasa si necesitamos crear una nueva clase concreta? ¿O nos vamos a otro proyecto con clases concretas diferentes?

Habría que modificar el código central, la lógica de negocio. Cualquier programador que meta una clase concreta nueva debería tocar esa parte, y eso no es recomendable. ¿Por qué no sacamos esa creación de clases concretas fuera de la lógica central (fuera del framework)?

Por eso no queremos acoplar la lógica de negocio a la creación de clases concretas.

Queremos que el código central se centre sólo en qué hace, trabajando contra una interface, sin conocer así a las clases concretas, y que la creación de estas esté desacoplada; si añadimos una nueva clase concreta no tendremos que tocar la parte central del código.

¿Cómo creamos entonces esas clases concretas?


Aquí entran en juego distintos patrones de diseño, y en ese caso concreto el Factory Method.

La definición del propósito de este patrón en el libro Design Patterns: Elements of reusable object-oriented software es la siguiente “Define una interfaz para crear un objeto, pero deja que sean las subclases quienes decidan qué clase instanciar. Permite que una clase delegue en sus subclases la creación de objetos”.

Aquí acaba está introducción con la necesidad de tener clases que nos ayuden a crear objetos. En sucesivos posts pondré ejemplos concretos del factory method pattern.

miércoles, 12 de octubre de 2016

Carga automática de clases. Parte II.

Tras haber visto un caso muy básico de cómo crear un atuloader en php llegamos al caso más habitual en el que tenemos una estructura de carpetas. Si organizamos el caso básico donde todo estaba en el mismo directorio podríamos tener la siguiente estructura.
[code] Directorio: Proyecto:
    Directorio: Entities
        Account.php
        Output.php
    autoload.php
    test_main_autoload.php [/code]

Parte II. Autoload: Implementación de PSR-4.


El primer pensamiento sería añadir a la función spl_auload_register del caso básico la nueva ruta para los requires, pero volveríamos al problema inicial si tenemos x directorios. Crear código que fuese comprobando en cada subdirectorio antes de pasar al siguiente si existe el fichero y si es así requerirlo no es algo muy eficiente; esto lo descartamos directamente.

Lo primero que debemos hacer, para encarar una solución óptima, es hacer que cada fichero sepa en qué directorio está. ¿Cómo? Utilizando namespaces.

¿Qué son los namespaces? .Digamos que es la forma de paquetizar ficheros en un mismo ámbito, es decir, es un espacio que creamos bajo un mismo nombre para agrupar clases, variables, funciones,… Es similar a los packages de java (sólo similar). Cada namespace puede tener el nombre que queramos poner.

En este caso pondremos a cada namespace un nombre base e iremos añadiendo la ruta dónde se encuentra cada directorio simulando una jerarquía de namespaces.

Veamos el fichero principal que está en el namespace base.

[code] namespace blog\autoload; use blog\autoload\Entities AS ent; require_once "autoload.php"; try { $account = new ent\Account(5); $output = ent\Output::getOutput(ent\Output::CONSOLE); $account->addAmount(2000); $account->payCommision(); $account->addAmount(50); $account->recoverAmount(20); $output->print($account->getTotal()); } catch (Exception $e) { echo($e->getMessage().PHP_EOL); } [/code]
Vemos que lo primero que se hace, en la primera línea, es asignar el fichero al namespace base blog\autoload (podemos poner el nombre que queramos) y a continuación utilizamos el namespace blog\autoload\Entities (base + primer directorio) y le damos un alias para acortarlo.

Ahora vamos a ver las clases Account y Output pertenecientes al namespace blog\autoload\Entities.

Clase Account:
[code] namespace blog\autoload\Entities; class Account { private $commision; private $amount; public function __Construct(int $percentage) { $this->commision = $percentage; } public function addAmount(int $amount) { assert($amount >= 0); $this->amount += $amount; } public function payCommision() { $this->amount = ( ( 100 - $this->commision ) * $this->getTotal() ) / 100 ; } public function recoverAmount(int $amount) { assert($amount >= 0); $this->amount -= $amount; } public function getTotal() : int { return $this->amount; } } [/code]
Clase Output:
[code] namespace blog\autoload\Entities; class Output { const CONSOLE = 1; const FILE = 2; private function __construct() { // Configure output } public static function getOutput(int $type) : Output { // Aquí deberíamos tener un factory method para devolver el objeto output adecuado y Outpt debería ser una clase abstracta. // Queda pendiente para otro post donde se muestre cómo generar objetos. if($type === 1) return new Output(); else throw new Exception("Wrong ouput selected."); // Si no existe un output adecuado deberíamos devolver un output base en vez de lanzar una excepción. // No tener un output adecuado no debería para la ejecución. } public function print($val) { echo("Total amount is: ".$val.PHP_EOL); } } [/code]
Vemos que ambos ficheros pertenecen al namespace blog\autoload\Entities, y es en el directorio Entities dónde se encuentran.

Hay que tener en cuenta un detalle antes de continuar; aunque el namespace contenga una ruta realmente no estamos asignando una ruta, estamos asignando un nombre que casualmente coincide con la ruta. Si hacemos que un fichero use el namespace vendor\dir1 no estaremos usando a su vez vendor\dir1\dir2 aunque el directorio dir2 esté dentro de dir1, son nombres de namespaces distintos, repito, no rutas, un namespace no contiene a otro.

Antes de ver el autoload analicemos los detalles y el patrón a seguir.

  • Podemos decir que el fichero ejecutable está en el namespace base, por lo que puede tener cualquier nombre, en este caso hemos decidido que sea blog\autoload\.
  • Cada clase debe tener el mismo nombre que el fichero que lo contiene (una clase por fichero). 
  • Cada fichero deberá pertenecer al namespace compuesto por el nombre del namespace base más las barras correspondientes y los directorios en los que está cada fichero. En este caso al estar en el directorio Entities que cuelga del directorio base su namespace es blog\autoload\Entities.
  • El nombre de las clases tiene la estructura namespace\subnamespace\..\Class. Por ejemplo la clase que llega al autoload realmente es la clase blog\autoload\Entities\Account. Es decir, su namespace más el nombre de la clase.
  • Se observa que el nombre de la clase es namespace_principal\directorio1\..\Clase, por lo que si eliminamos el namespace base, y añadimos un .php al final, tenemos exactamente dónde está el fichero guardado respecto al directorio base. Ejemplo: __DIR__.\Entities\Account.php.

Siguiendo estos puntos ya tenemos un patrón: el nombre del namespace indica dónde está cada fichero respecto a un namespace base.

Pues ya es hora de ponernos a construir un fichero autoload. ¿O no? ¿Para qué crear el autoload si ya alguien lo ha creado por nosotros?

La gente de PHP-FIG ya ha creado un autoloader que podemos utilizar. Lo podéis encontrar en su recomendación estándar 4 (PSR-4 o PHP Standard Recommendation 4).

Aquí lo hemos adaptado a nuestro ejemplo modificando las variables $prefix y $base_dir y añadiendo un echo para imprimir la clase requerida.
[code] // Implementation of PSR-4 spl_autoload_register(function ($class) { echo("Requiriendo fichero: ".$class.".php".PHP_EOL); // project-specific namespace prefix $prefix = 'blog\\autoload\\'; // base directory for the namespace prefix $base_dir = __DIR__.'/'; // does the class use the namespace prefix? $len = strlen($prefix); if (strncmp($prefix, $class, $len) !== 0) { // no, move to the next registered autoloader return; } // get the relative class name $relative_class = substr($class, $len); // replace the namespace prefix with the base directory, replace namespace // separators with directory separators in the relative class name, append // with .php $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php'; // if the file exists, require it if (file_exists($file)) { require_once $file; } }); [/code]
Con esto ya tenemos nuestro fichero autoload.php que hemos requerido anteriormente en nuestro fichero principal.

Lo ejecutamos y obtenemos el siguiente resultado.
[code] Requiriendo fichero: blog\autoload\Entities\Account.php Requiriendo fichero: blog\autoload\Entities\Output.php Total amount is: 1930 [Finished in 0.4s] [/code]
La ejecución ha sido satisfactoria.

De esta forma, requiriendo el autoload y usando un namespace (blog\autoload\Entities), podemos autocargar todas las clases que contenga este sin tener que hacer un require por cada fichero.

Código en GitHub

domingo, 9 de octubre de 2016

Carga automática de clases. Parte I.

Es frecuente encontrar, al comienzo de ficheros php, largas listas de requires con las clases que se van a utilizar. Y en esos otros ficheros que requerimos encontramos a su vez otras listas de requerimientos. Es molesto tener que escribirlos todos, o borrarlos si movemos instanciaciones, pero tiene solución creando un cargador de clases.

Parte I. Autoload simple.



Un sencillo ejemplo en el cual todos los ficheros php están en el mismo directorio.

Tenemos el siguiente fichero php:
[code] require_once "Account.php"; require_once "Output.php"; try { $account = new Account(5); $output = Output::getOutput(output::CONSOLE); $account->addAmount(2000); $account->payCommision(); $account->addAmount(50); $account->recoverAmount(20); $output->print($account->getTotal()); } catch (Exception $e) { echo($e->getMessage().PHP_EOL); } [/code]
Vemos que utiliza 2 clases: Account y Output. Este caso es muy simple, pero si utilizáramos 50 clases deberíamos hacer un listado con 50 requires. Una locura no apta para dedos sensibles a escribir una y otra vez cosas que no aportan nada.

¿Qué no aporta nada? ¿Y qué hacemos entonces? Que si lo quito porque no quiero escribirlo me salta el siguiente error:
[code] ‘Fatal error: Class 'Account' not found’ [/code]
Pues aprovechemos la siguiente función de php: spl_autoload_register.

Vamos a crear un fichero básico (muy básico) llamado autoload_basic.php.
[code] spl_autoload_register(function ($class) { echo("Requiriendo fichero: ".$class.".php".PHP_EOL); require_once $class.".php"; }); [/code]
Si no entiendes muy bien qué ocurre, y por qué hay una función cómo parámetro, tiene que ver con las closures. ¿El qué? Es tema para otro post, pero quedémonos con el siguiente resumen: el parámetro que acepta la función spl_autoload_register es de tipo callable, es decir, lo que se le pasa es una llamada de retorno. La función que se pasa como parámetro es una closure o función anónima, y su tipo es Closure. Las funciones anónimas, es decir, los tipos Closure también se pueden pasar como un parámetro callable.

La función que se registra en spl_autoload_register es el autoload que queremos que se ejecute cada vez que se quiere instanciar una clase.

Cambiemos la función principal:
[code hl="1"] require_once "autoload_basic.php"; try { $account = new Account(5); $output = Output::getOutput(output::CONSOLE); $account->addAmount(2000); $account->payCommision(); $account->addAmount(50); $account->recoverAmount(20); $output->print($account->getTotal()); } catch (Exception $e) { echo($e->getMessage().PHP_EOL); } [/code]
Ya está, todo listo para probar.

Fijemos antes que los requires a cada fichero han desaparecido y ahora estamos haciendo un único require de autoload_basic.php.

Ejecutemos:
[code] Requiriendo fichero: Account.php Requiriendo fichero: Output.php Total amount is: 1930 [Finished in 0.1s] [/code]
Con este resultado sacamos la siguiente conclusión:
  1. El ejecutable trata de instanciar una clase.
  2. El fichero que contiene la clase no ha sido requerido, por lo que se ejecuta la función autoad que se ha registrado a través de spl_autoload_register.
  3. La variable $class es el nombre de la clase que se trata de instanciar.
  4. Dentro de la función autoload se hace el require de la clase.
  5. Ya no hay que hacer x requires en el fichero principal.

Todo perfecto y en orden, salvo que todo no puede ser siempre tan simple.

NOTA: El fichero autoload_basic.php, para este caso, podría ser de la siguiente forma:
[code] spl_autoload_register(); [/code]
Si la función spl_autoload_register no recibe ningún parámetro usa directamente como variable callable por defecto la función spl_autoload que a su vez tiene como parámetro el nombre de la clase que se instancia. He preferido añadir la closure para que tenga el mismo efecto pero que se vea qué hace.

Código en GitHub

domingo, 25 de septiembre de 2016

Contra los largos métodos

Estos últimos días he estado revisando código para el testeo (no hay tests unitarios) de una aplicación realizada en symfony. He estado tratando de entender qué hace para poder ver si funciona o no.

Bien, en un punto, probando diferentes tipos de alarmas que heredan de una clase madre, he visto que cada una de esas clases tiene un método run. Hasta ahí bien, pero me he encontrado dos cosas que no me han gustado.

  1. El polimorfismo no se usa en una estructura, ni pudiendo pasar distintos objetos cómo parámetros para ejecutar el método a posteriori. Cada método run de cada alarma se ejecuta de forma autónoma en condiciones diferentes nada más instanciar el objeto de cada alarma concreta. 
  2. El método run es el único método de la clase concreta y cada uno tiene entre 200 y 400 líneas.

Evidentemente entender a veces qué hacen esos métodos tan largos me está generando ciertos quebraderos de cabeza, y alguna vez me pierdo y tengo que volver atrás, cómo quien se duerme viendo una película y busca dónde se quedó antes de sucumbir.

Así que he aprovechado para resumir qué dice Martin Fowler en su libro “Refactoring: Improving the design of existing code”.

Recordemos que un método debe hacer una única cosa, y en 300 líneas de método me da que caben bastantes.

Basta decir que lo primero que dice, como antítesis del enunciado “Long Methods”, es que los métodos deben ser cortos. ¿Pero cómo? Ahí viene la parte interesante.

He decidido no meter aquí ejemplos de código para no hacerlo muy largo y que se pueda leer como un simple manual con recomendaciones a seguir. Ya vendrá el código concreto en otros posts.


Extraer métodos.



Lo más básico es que si hay código duplicado dentro del método, o que hace casi lo mismo en varias partes, hay que sacarlo como un método en sí mismo. Esto es así siempre. El código no se duplica.

Hay veces en los que hay un trozo de código que dan ganas de comentar para que se pueda entender, por lo que eso tiene toda la pinta de que se puede extraer en un método. Aquí hay que tener cuidado y no extraer métodos por extraerlos. Por ejemplo, si vas a extraer 2 o 3 líneas (o alguna más) quizás no merezca la pena, o quizás sí. Ahí entra el caso concreto y la valoración del contexto. ¿El método tiene entidad por sí mismo? ¿Tendría sentido sin el método del que se ha extraído?

Los métodos extraídos deben tener buenos nombres. El nombre debe contener la intención del método, no cómo hace lo que hace. Esto es importante. ¿Es difícil elegir el nombre con la intención? Quizás es que tiene más de una intención y no es un único método a extraer. Resumiendo, el nombre del método debe decir lo mismo que el comentario que se iba a añadir, pero sólo en un nombre.


Reemplazar variables temporales con una consulta.



Si al método extraído se le pasan muchos parámetros que no son más que variables temporales, creadas únicamente para contener resultados de ciertas expresiones, tenemos un problema. Muchos parámetros complican entender qué hace el método, y por otra parte estamos acoplando el método extraído a resultados calculados en el largo método que queremos acoplar. No aportamos comportamiento sólido a la clase con ese nuevo método.

Hay que eliminar esos parámetros. IMPORTANTE: Esto aplica a variables temporales que sólo se asignan una vez, ya que vienen de una expresión que ha realizado un cálculo, y dicha expresión no tiene efectos colaterales. Es decir, no modifica el estado del objeto. Un ejemplo típico es el cálculo a base de variables de clase para obtener un valor que se usa temporalmente. Ese cálculo, que no modifica ninguna de las variables de clase, se puede extraer en un método, aportando comportamiento a la clase.


Introducir un objeto con los parámetros.



Vale, tenemos parámetros que no son variables temporales, son variables que se usan a lo largo del método que incluso pueden cambiar durante la ejecución, y encima vemos que habitualmente se pasan de forma conjunta. ¿Cómo procedemos si no queremos pasar una gran cantidad de parámetros al método extraído? Siempre se puede pasar un array como parámetro, pero eso sería sólo en el caso de que tuviésemos pocos parámetros sin ningún tipo de comportamiento. ¿En esos casos merece la pena crear una nueva clase? Lo más probable es que no.

Pero en el caso en el que durante la ejecución del método las variables a pasar puedan cambiar, o sean partícipes de expresiones (duplicidad de código asegurada), lo ideal es extraer esas variables, y su comportamiento, que será más evidente al agruparlas, en una clase para pasar así un objeto como parámetro. Esto facilitará acortar bastante el método y encapsular variables y comportamiento en un único objeto, lo que a la larga favorecerá la comprensión y modificación del código.

Resumiendo, vamos a crear, a base de variables y el comportamiento que conllevan, un objeto que se pasará como parámetro al método extraído.


Pasar el objeto completo.



Bueno, este es muy sencillo, si pasamos cómo parámetros muchas llamadas a métodos de un objeto, o incluso muchas variables de clase del propio método, siempre podemos pasar el objeto completo, aunque este sea el propio objeto desde el que se pasan los parámetros si estamos pasando un montón de variables de clase recuperables con getters.


Extraer un método como un método de otro objeto.



Como ya hemos hecho anteriormente al introducir un objeto con los parámetros, volvemos a crear una nueva clase para reducir código de un método largo. Esta vez hay una diferencia. Se extrae un método y, a partir del nombre de ese método, se crea una clase que se instancia y usa. ¿En qué casos hacemos esto?

Aquí volvemos a encontrarnos variables temporales que se usan en el método original pero, debido a su complejidad, no pueden extraerse con una consulta. La idea a priori es simple (aunque en el fondo compleja); se crea una clase con variables de clase que representan esas variables temporales, se calculan en el constructor, y se crea un método con nombre tipo “compute”, “calculate” o similar. Teniendo ahora ese método aislado podemos aplicar los pasos anteriores para reducirlo, en la nueva clase, en métodos más pequeños.

En resumen, hemos creado un objeto a partir de un método que se instancia para ejecutar el método. Esto, si no se hace con cuidado, puede generar en clases erróneas que no es necesario crear y que realmente no representan una entidad. Otra forma de refacrorizar es eliminar clases que no lo son porque sólo hacen una cosa y no representan ninguna identidad. Este caso, por tanto, hay que hacerlo con mucho cuidado; un ejemplo sería el patrón “strategy pattern” en el cual se extrae comportamiento de una clase para usar una estrategia u otra tirando de composición en vez de herencia.


Descomponer un condicional.



Hemos encontrado una sentencia if-elseif-else muy compleja que no favorece la legibilidad y que, en algunos casos, puede incluso matar unas cuantas neuronas al tratar de seguir su lógica.

Un ejemplo sería un if tipo si es A y no es B y tampoco es C pero tiene que tener D, y todo ello lo podemos resumir en un es E. Creamos un método llamado E que maneja las comprobaciones múltiples, por lo que en el condicional sólo se llama a E dejándolo mucho más claro. Recordemos, el método tiene que tener un nombre que deje totalmente clara la intención del condicional compuesto y dejar el cómo en la implementación del método.

lunes, 15 de agosto de 2016

Testeando métodos privados en PHP

La idea de este post es hacer testeo unitario de distintos métodos de una clase, aunque estos sean privados. Lo ideal sería utilizar un framework especializado, como puede ser PHPUnit, pero para simplificar voy a realizar testeo a “pelo”.

Cuando estamos testeando una clase siempre llega el momento en el que nos damos cuenta que no es posible testear un método privado de forma unitaria, pero queremos hacerlo; siempre lo estamos testeando indirectamente a través de un método público.

¿Cómo podemos testear de forma unitaria ese método privado?

La solución es utilizar reflexión (reflection).

Tenemos la siguiente clase llamada RobotCar:
[code] /** * Robot car moving along a road with several lanes. It can just go ahead and change rails left or right. * It is able to accelerate */ class RobotCar { private $x; private $y; private $acceleratorFactor; public function __construct() { $this->x = 0; // position in axe x $this->y = 0; // position in axe y $this->acceleratorFactor = 1; } public function changeToLeft ( array $viewAtLeft = array() ) { if($this->isSideFree($viewAtLeft)) $this->changeX(-1); } public function changeToRight ( array $viewAtRight = array() ) { if($this->isSideFree($viewAtRight)) $this->changeX(1); } private function changeX($mov) { $this->x += $mov; } private function isSideFree( array $view ) : bool { if(empty($view)) return true; return false; } public function goStraight() { $this->y += $this->acceleratorFactor; } public function getPosition() : string { return "X: ".$this->x." - Y: ".$this->y; } public function accelerate() { $this->acceleratorFactor += 1; } } [/code]
Esta clase representa un coche robot que, en un tablero de varios carriles (infinitos para simplificar), puede avanzar sólo hacía adelante (desplazamiento en eje y), con un factor de aceleración configurable, cambiando de carril si es necesario (desplazamiento en eje x).

Vemos que hay dos métodos, changeToLeft y changeToRight, que utilizan el mismo método privado isSideFree para verificar si es posible realizar el cambio de carril:
[code] private function isSideFree( array $view ) : bool { if(empty($view)) return true; return false; } [/code]
El método isSideFree recibe un array llamado $view que contiene todo objeto del mundo real que se ve antes de realizar el cambio y devuelve un booleano. ¿Cómo probarlo de forma unitaría?

Vamos a utilizar la clase de PHP ReflectionClass.

El primer paso es instanciar un objeto de dicha clase y extraer el método privado que vamos a utilizar.
[code] $reflected = new ReflectionClass("RobotCar"); $method = $reflected->getMethod("isSideFree"); [/code]
Ya hemos obtenido el método en la variable $method. El método es privado, por lo tanto hay que hacerlo accesible desde fuera:
[code] $method->setAccessible(true); [/code]
Ahora sólo queda invocar el método:
[code] $isFree = $method->invokeArgs(new RobotCar(), array(array("Arbol"))); [/code]
Vemos que los parámetros de invokeArgs son un objeto de la clase RobotCar y un array con los distintos parámetros del método a ejecutar. En este ejemplo pasamos un objeto recién instanciado, pero también en posible pasar un objeto instanciado anteriormente y modificado.

De esta forma, gracias a la técnica de reflexión, podemos testear métodos privados de forma unitaría como si se tratara de métodos públicos.

Probemos la clase con el siguiente código:
[code] $car = new RobotCar(); echo($car->getPosition().PHP_EOL); $car->goStraight(); echo($car->getPosition().PHP_EOL); // x = 0 $car->changeToLeft(); echo($car->getPosition().PHP_EOL); // x = -1 $car->goStraight(); $car->changeToLeft(array("Other Car")); echo($car->getPosition().PHP_EOL); // x = -1 $car->accelerate(); $car->goStraight(); $car->changeToRight(array()); // X = 0 echo($car->getPosition().PHP_EOL); // Test RobotCar::isSideFree. Is it possible? $reflected = new ReflectionClass("RobotCar"); $method = $reflected->getMethod("isSideFree"); $method->setAccessible(true); echo("\nTest private method RobotCar::isSideFree if there is a tree."); $isFree = $method->invokeArgs(new RobotCar(), array(array("Tree"))); assert(!$isFree,"There is a Tree, assertion must be false."); echo("\nTest private method RobotCar::isSideFree if there is nothing."); $isFree = $method->invoke(new RobotCar(), array()); assert($isFree, "There is nothing, assertion must be true."); echo("\nTest private method RobotCar::isSideFree if there is a dog on a big stone (test incorrect)."); $isFree = $method->invokeArgs(new RobotCar(), array(array("Big Stone", "Dog"))); assert($isFree,"There is a dog on a big stone, assertion must be false."); // The test is wrong inentionallity. [/code]
EL resultado devuelve:
[code] X: 0 - Y: 0 X: 0 - Y: 1 X: -1 - Y: 1 X: -1 - Y: 2 X: 0 - Y: 4 Test private method RobotCar::isSideFree if there is a tree. Test private method RobotCar::isSideFree if there is nothing. Test private method RobotCar::isSideFree if there is a dog on a big stone (test incorrect). Warning: assert(): There is a dog on a big stone, assertion must be false. failed in \src\test_reflection.php on line 96 [/code]
Vemos que los 2 primeros assertions no saltan ya que tanto el resultado del método a testear como el test son correctos. El tercer assert lanza un warning porque el resultado no es el esperado. Nota: Este tercer assert es incorrecto, lo correcto sería:
[code] assert( ! $isFree,"There is a dog on a big stone, assertion must be false."); [/code]
ya que se esperaría un false. He falseado el test para demostrar que este funciona correctamente y detecta el valor no esperado.

De esta forma se puede profundizar en el testeo de clases.

Recomiendo ver la documentación de la clase ReflectionClass para ver todas sus posibilidades, lo mostrado aquí es una pequeña parte.

Código en GitHub

miércoles, 20 de julio de 2016

Clases anónimas en php7

Ya ha sido liberado php7, lo que implica una renovación del lenguaje. Una de las novedades que trae son las clases anónimas.

¿Qué es una clase anónima? Simplificando, es una clase que no existe como tal pero que puede instanciar un objeto. Esto quiere decir que podemos crear un objeto a partir de una clase sin nombre, que no ha sido previamente creada.

¿Para qué nos puede servir? Veámoslo con un ejemplo.

Tenemos la siguiente clase Contract que tiene una variable de clase privada llamada $contractDate.
[code]class Contract { private $contractDate; private $contractMonths; public function __construct( string $date, int $contractMonths = 12) { $this->contractMonths = $contractMonths; $this->contractDate = new DateTime($date); } public function getEndDate() { (...) } (...) }[/code]
La variable $contactDate representa una fecha, es decir, tenemos como opciones: un String, un objeto DateTime (mejor), …

Vemos que el constructor de la clase Contract recibe dos parámetros: un String con la fecha y un integer con el número de meses de duración del contrato. Para manejar fechas lo más seguro es utilizar la propia clase de php DateTime, pero la fecha de finalización del contrato se calcularía en un método de la Clase contract getEndDate(), y esta podría guardarse en una variable de clase $endDate o devolverse calculada al vuelo en un método.

Una tercera opción sería pensar que, si la responsabilidad de las fechas está en la clase DateTime, ¿por qué no darle esa responsabilidad? Pues ya está, creemos la clase ContractDate que extendería DateTime, añadiendo sólo un método llamado getEndDate(). Tendríamos un nuevo fichero (un clase por fichero como buena práctica) con la clase ContractDate que sólo vamos a utilizar en la clase Contract pero estaría disponible en toda la aplicación. Aquí entran en juego las clases anónimas para evitar dicha situación y poder extender DateTime sin generar nuevos ficheros.

Modificamos el constructor.
[code hl="11"]class Contract { private $contractDate; const DEFAULT_CONTRACT_MONTHS = 12; public function __construct( string $date, int $contractMonths = self::DEFAULT_CONTRACT_MONTHS) { $this->contractMonths = $contractMonths; $this->contractDate = new class() extends DateTime { public function getEndDate( int $months, string $dateFormat = 'Y-m-d') : string { $date = new DateTime($this->format('Y-m-d')); $date->add(new DateInterval("P".$months."M")); $date->sub(new DateInterval("P1D")); return $date->format($dateFormat); } }; } }[/code]
Vemos que al inicializar $this->contractDate en el constructor escribimos new Class() extends DateTime { … }. Ahora tenemos un objeto de tipo clase anónima, pero a su vez es de tipo DateTime.

Ahora el método getEndDate() en la clase Contract ya no sería necesario si no queremos exponer ese dato fuera de la clase Contract.

Añadimos nuevos métodos públicos a la clase Contract. Uno de ellos se encargará de utilizar la fecha de finalización.
[code hl="13"]public function changeContractMonths(int $months) { $this->contractMonths = $months; } public function printStartDate() { echo("Start Date is ".$this->contractDate->format('Y-m-d').PHP_EOL); } public function printEndDate() { echo("End Date is ".$this->contractDate->getEndDate($this->contractMonths).PHP_EOL); }[/code]
De esta forma hemos visto como:
  • Crear un objeto a partir de una clase que no existe (anónima).
  • Extender una clase existente sin necesidad de crear una nueva clase.

Si añadimos la función notifyEach2Weeks5Times() vemos que el objeto generado a partir de la clase anónima se sigue comportando como un objeto de tipo DateTime.
[code]public function notifyEach2Weeks5Times() { $interval = new DateInterval('P2W'); $period = new DatePeriod($this->contractDate, $interval, 5, DatePeriod::EXCLUDE_START_DATE); foreach ($period as $nextDateTime) { echo $nextDateTime->format('Y-m-d').PHP_EOL; } }[/code]
Probamos la clase Contract con el código:
[code] echo("Contrato de 12 meses desde la fecha actual.".PHP_EOL); $contract = new Contract(date("Y-m-d"), 12); echo($contract->printStartDate()); echo($contract->printEndDate()); echo("Cambiamos los meses de contrato a 24.".PHP_EOL); $contract->changeContractMonths(24); echo($contract->printEndDate()); echo PHP_EOL; echo("Recordatorio cada 2 semanas 5 veces:".PHP_EOL); $contract->notifyEach2Weeks5Times(); [/code]
El resultado obtenido es:
[code]Contrato de 12 meses desde la fecha actual. Start Date is 2015-12-17 End Date is 2016-12-16 Cambiamos los meses de contrato a 24. End Date is 2017-12-16 Recordatorio cada 2 semanas 5 veces: 2015-12-31 2016-01-14 2016-01-28 2016-02-11 2016-02-25[/code]
Fichero en Git Hub

viernes, 1 de julio de 2016

¿Por qué hacer crecer la blogosfera?

¿Por qué un blog? ¿Con qué fin embarcarse en un proyecto que, con toda seguridad, no reportará beneficios al autor ni nada nuevo al mundo del desarrollo pero sí consumirá tiempo? Estas son las preguntas que seguro se habrá formulado todo aquel que haya pensado hacer algo parecido.

Podría empezar diciendo, en base a lo que cree mucha gente, que es por un ego necesitado de darse a conocer, de tener visitantes, de revolucionar el mundo del desarrollo, de ... pero me estaría engañando a mi mismo. No, la respuesta es más simple de lo que parece, todo se resume con una frase que ya muchos han debido escuchar: "si no mejoras, empeoras".

Por tanto, para ser claros, este blog no pretende, en ningún caso, ni mucho menos de forma premeditada, dar grandes lecciones de cómo desarrollar, ni mostrar nuevas técnicas que no estén en otros sitios, ni ser un lugar de referencia. El único fin es que el autor del propio blog aprenda o repase o refresque o fije conceptos que con el tiempo se acaban diluyendo. Si de paso alguien encuentra ayuda a sus problemas, que serán parecidos a los del autor, eso que sacamos todos de provecho.

Cuando leemos un libro (recomiendo hacerlo de vez en cuando) o blog sobre algún nuevo tema que desconocíamos tendemos a tratar de aprender de forma rápida, sin pausar ni digerir, a fin de cuentas según lo tenemos delante lo vamos entendiendo, por tanto, siempre, la asimilación no llega a producirse cómo debiera y el olvido llega un día y ni nos enteramos. ¿Qué mejor forma de asimilar lo aprendido que explicando a otra persona ese algo nuevo que hemos descubierto? Ese es, precisamente, el fin de este blog.

Empecemos pues.