viernes, 28 de septiembre de 2018

Plantilla para proyectos en PHP con TDD y DDD con composer


En esta publicación voy a explicar cómo implementar la base para un proyecto o librería que queramos desarrollar con TDD + DDD utilizando Composer desde cero.

Para desarrollar con TDD vamos a necesitar un framework de pruebas. En este caso se va a utilizar PHPUnit que es un framework de pruebas muy extendido. Para instalar los paquetes como PHPUnit disponemos de varias herramientas siendo Composer de las más comunes.

Otro problema al que nos enfrentamos a la hora de llevar a cabo el proyecto es la configuración del fichero de composer para que todo funcione correctamente. Así que voy a explicar cómo llevar a cabo cada paso para tener un proyecto desarrollado con TDD + DDD con Composer.

Por supuesto, el control de versiones es imprescindible en cualquier proyecto así que en este caso se va a utilizar Git.

Lo primero es crear una carpeta con el nombre del proyecto. Así que, suponiendo que tenemos una carperta “projects” en nuestra home de usuario, desde una consola creamos la carpeta con el nombre del proyecto, por ejemplo: “php-tdd-ddd-template-composer”.

mkdir ~/projects/php-tdd-ddd-template-composer

Una vez creada accedemos a ella.

cd ~/projects/php-tdd-ddd-template-composer

Ahora hay que iniciar un proyecto en Git. Así que creamos nuestro flamante proyecto en git con el siguiente comando.

git init

Siempre es recomendable añadir un archivo README.md ya que tanto para otros usuarios como para nosotros mismo en un futuro nos va a ser útil. No hay un estándar para hacer ficheros de este estilo aunque seguro que con una rápida búsqueda puedes encontrar recomendaciones o plantillas.

Una vez creado el archivo README.md lo incluimos en el repositorio.

git add .

Hacemos “commit” del mismo.

git commit -m “Add README.md” file.

Creado el proyecto y el repositorio, el siguiente paso es crear un archivo de composer para que sea más fácil la administración de los distintos paquetes.

composer init

Este comando va a crear una serie de preguntas

Package name (<vendor>/<name>) [eltortuganegra/php-tdd-template-composer]:
Description []: Template for php projects for develop with TDD. Composer is used for install project.
Author [, n to skip]: Jorge Sánchez <jorge.sanchez@eltortuganegra.com>
Minimum Stability []:
Package Type (e.g. library, project, metapackage, composer-plugin) []:
License []: MIT
Would you like to define your dependencies (require) interactively [yes]?
Search for a package:
Would you like to define your dev dependencies (require-dev) interactively [yes]? Yes
Search for a package: phpunit

Found 15 packages matching phpunit

[0] phpunit/phpunit
[1] phpunit/phpunit-mock-objects
[2] phpunit/php-token-stream
[3] phpunit/php-timer
[4] phpunit/php-text-template
[5] phpunit/php-file-iterator
[6] phpunit/php-code-coverage
[7] symfony/phpunit-bridge
[8] phpunit/phpunit-selenium
[9] johnkary/phpunit-speedtrap
[10] codedungeon/phpunit-result-printer
[11] jean85/pretty-package-versions
[12] brianium/paratest
[13] phpunit/dbunit
[14] spatie/phpunit-snapshot-assertions

Enter package # to add, or the complete package name if it is not listed: 0

Los paquetes que vamos a instalar son, de momento, phpunit en su última versión.
En este caso añadimos un 0 y pulsamos enter, lo que nos lleva a buscar otro paquete. Como no queremos añadir más paquetes. Pulsamos enter.

Para ver las dependencias escribimos “yes” y pulsamos enter.

Search for a package:

{
"name": "eltortuganegra/php-tdd-template-composer",
"description": "Template for php projects for develop with TDD. Composer is used for install project.",
"type": "project",
"require-dev": {
"phpunit/phpunit": "^7.3"
},
"license": "MIT",
"authors": [
{
"name": "eltortuganegra",
"email": "jorge.sanchez@eltortuganegra.com"
}
]
}

Do you confirm generation [yes]? yes
Would you like the vendor directory added to your .gitignore [yes]? yes


Sólo queda confirmar y se procede a la generación del archivo “composer.json”.

Ahora pasamos a instalar con composer todas las dependencias.

composer install

En este momento se puede observar como se ha creado una carpeta «vendor» donde se han instalado todas las dependencias.

Llega el momento de organizar las distintas carpetas del proyecto. Cada uno tiene su organización de carpetas pero una buena manera de empezar es crear una carpeta «tests» y otra «src» donde se almacenará el código de los tests (sí, ¡las pruebas se hacen primero!).

Para comprobar si Phpunit está funcionando vamos a crear una prueba por defecto: DefaultTest.php

Cuando ejecutamos phpunit para que ejecute la prueba

./vendor/bin/phpunit tests/DefaultTest.php

Debería devolver el siguiente resultado.

PHPUnit 7.3.5 by Sebastian Bergmann and contributors.

. 1 / 1 (100%)

Time: 98 ms, Memory: 4.00MB

OK (1 test, 1 assertion)

Con esta sencilla prueba se verifica que Phpunit está funcionando correctamente. Aún que el propósito es probar el código fuente así que vamos a añadir una prueba donde se utilice una clase que esté ubicada en la carpeta destinada a tal fin, la carpeta «src».

Una prueba simple podría ser crear una instancia de la clase ubicada en la carpeta «src» y comprobar que la nueva instancia es una instancia de esa clase.

Ejecutamos la prueba recién creada para confirmar que da un error, tal y como se indica en TDD.

PHPUnit 7.3.5 by Sebastian Bergmann and contributors.

.E 2 / 2 (100%)

Time: 83 ms, Memory: 4.00MB

There was 1 error:

1) DefaultTest::testDeleteMeShouldCreateAnInstanceWhenWeCreateAnInstance
Error: Class 'DeleteMe' not found

/home/vagrant/www/php-tdd-template-composer/tests/DefaultTest.php:17

ERRORS!
Tests: 2, Assertions: 1, Errors: 1.

Como se puede apreciar la ejecución de la prueba da un error. Ahora hay que crear la clase “DeleteMe” en la carpeta «src» para que pasar la prueba. Añadimos el namespace «app».
En este caso, si volvemos a ejecutar la prueba vamos a tener el mismo error. ¿Cómo es posible si hemos creado la clase? El problema es que no estamos indicando que cargue las clases automáticamente. Para configurarlo hay que modificar el fichero de configuración de composer y añadirle un atributo “autoload”.

{
"name": "eltortuganegra/php-tdd-template-composer",
"description": "Template for php projects for develop with TDD. Composer is used for install project.",
"type": "project",
"require-dev": {
"phpunit/phpunit": "^7.3"
},
"license": "MIT",
"authors": [
{
"name": "eltortuganegra",
"email": "jorge.sanchez@eltortuganegra.com"
}
],
"autoload": {
"classmap": [
"src/"
]
}
}

Actualizamos composer para que incorpore los cambios en el fichero de configuración.

composer dump-autoload

Y volvemos a ejecutar la prueba. Con el siguiente resultado.

./vendor/bin/phpunit tests/DefaultTest.php
PHPUnit 7.3.5 by Sebastian Bergmann and contributors.

.. 2 / 2 (100%)

Time: 67 ms, Memory: 4.00MB

OK (2 tests, 2 assertions)

Llegados a este punto, tenemos la base del proyecto funcionando. Una carpeta «tests» donde se almacenan todos las pruebas y una carpeta «src» donde se almacena todo el código que tiene que pasar las pruebas.

Según el DDD no hay una organización estándar de estructuras así que cada uno es libre de organizarla como considere oportuno. En el libro de Eric Evans Domain-Driven Design book tiene un ejemplo “Cargo Sample” del cual se puede encontrar implementaciones en GitHub como como el php-ddd-cargo-sample. En el se puede apreciar la estructura de carpetas que utilizan.

Sin embargo, esta publicación es para crear un proyecto sencillo y de cero por lo que, en principio y como ejercicio paso a paso, crearía una carpeta por cada concepto que se detalla en DDD.

Mi solución sencilla para aquellos que están empezando y quieren empezar a introducirse en este mundo es utilizar la plantilla para proyectos en php con TDD y DDD.

En esta plantilla hay una estructura de carpetas que albergan un clase por defecto por cada concepto y su correspondiente prueba en la carpeta «tests».


miércoles, 5 de septiembre de 2018

Introducción a DDD

Qué es el DDD


El diseño guiado por el dominio, en inglés «domain-driven design», o DDD, es un enfoque para el desarrollo de software.

El DDD no es una tecnología ni una metodología, sino un conjunto de prácticas y terminologías que aportan valor a la hora de tomar decisiones sobre el diseño de software.

El DDD tiene más que ver con que ver con sobre el debatediiscusiónscusión debate,, la escucha, el entendimiento, el descubrimiento y el valor de negocio en un esfuerzo por centralizar el conocimiento del dominio. Si se es capaz de entender el negocio se puede participar en el proceso de descubrimiento del modelo de software para producir un lenguaje ubicuo.

El lenguaje ubicuo es el lenguaje común de los expertos del dominio y los desarrolladores. Este facilita la comunicación entre todas las partes implicadas, por lo que todos saben que está pasando con el negocio.

Otra característica del DDD es que todo está basada en el dominio siendo este una abstracción del negocio.

Una vez que los conceptos del dominio están definidos en el lenguaje común se puede modelar el mismo. Un modelo de dominio es una parte muy específica del dominio de negocio. Este modelo se implementa como un modelo objeto con unos datos y un comportamiento con un significado literal y preciso dentro dcon el negocio.

Nunca se trata de modelar todo el negocio en un único y enorme modelo de dominio si no que los modelos tienden a ser pequeños y muy enfocados.

Qué valor aporta DDD


El DDD aporta, principalmente, los siguientes valores:

  • Involucra a los expertos de dominio y a los desarrolladores durante el diseño del software por lo que este tiene sentido para todos los implicados y no sólo para los desarrolladores.
  • El software desarrollado tiene un significado semántico para los expertos de dominio.
  • Supone una mejor comprensión del negocio para todos los implicados ya que el negocio está en constante evolución.
  • El conocimiento del software no está centralizado exclusivamente en los desarrolladores si no que al estar involucrado el negocio estos también tienen el conocimiento.
  • Mejora la comunicación entre los expertos del dominio y los desarrolladores al utilizar el lenguaje ubicuo con lo que no se necesita hacer traducciones.
  • El DDD provee técnicas de desarrollo de software que dirigen el diseño estratégico y táctico.

El diseño estratégico tiene el objetivo de dirigir el negocio por lo que se centra en definir los distintos aspectos del negocio y priorizar aquellos que aporten un mayor valor.

El diseño táctico dispone de herramientas de modelado para el desarrollo de los entregables de software ejecutables. Estas herramientas permiten analizar y desarrollar software con el modelo mental de los expertos de dominio.

Cuando hay que usar el DDD


El factor fundamental a tener en cuenta es si la inversión derivada de aplicar el DDD aporta valor al proyecto, pues hay que hacer una inversión de tiempo y esfuerzo.

El DDD no aporta un valor sustancial a las partes que son triviales y que son fácilmente reemplazables. Sin embargo, sí aporta valor en aquellas áreas más complejas, las más valorables e importantes y de mayor valor para el sistema.

A estas áreas más importantes las llamamos «Core Domain» y en segunda prioridad «Supporting Subdomains». Estas son las que aportan mayor valor al negocio.

Uno de los objetivos del DDD es modelar un sistema complejo de la manera más simple posible por lo que nunca se debería usar el DDD para obtener hacer la solución más compleja.

La complejidad dependerá de cada negocio por lo que puede ser difícil definir qué es complejo. Una estrategia alternativa es definir qué es trivial. Una vez establecido qué no es trivial el equipo tendrá que valorar si merece la pena hacer la inversión de hacer uso del DDD.

Cómo hacer DDD


Para llevar el DDD a la práctica hay que dominar dos aspectos características: la ubicuidad del lenguaje y los contextos delimitados.

Lenguaje ubicuo

El lenguaje ubicuo es un lenguaje que desarrollan y comparten todos aquellos que están implicados en el desarrollo del proyecto sin importar su rol.

Los expertos de negocio tendrán un mayor peso a la hora de desarrollar el lenguaje ya que son ellos quienes conocen el negocio. A pesar de tener un mayor peso deben trabajar junto con el resto del equipo, como los desarrolladores, para confeccionar un modelo de dominio de manera que se definan los mejores conceptos, términos y significados. El lenguaje evoluciona a medida que los avances se van alcanzando.

Algunas recomendaciones para definir el lenguaje ubicuo:

  • Tener una representación gráfica del dominio de manera que se puedan apreciar los distintos elementos que lo componen.
  • Crear un glosario de términos con los elementos del dominio.
  • Cualquier otro tipo de documentación aclare los conceptos, términos y significados del dominio.
  • Cualquiera de las anteriores tiene que tener la aprobación del resto del equipo. Estas podrán ir evolucionando con el tiempo por lo que habrá que ir actualizándolas.

Contexto delimitado

Los contextos delimitados son límites conceptuales del sistema. Estos límites resaltan un contexto y, al igual que en el lenguaje natural, los distintos términos y frases tienen un significado específico dentro de ese contexto. Cualquier uso de un término fuera de ese contexto podría tener un significado diferente.

Los contextos delimitados son tan pequeños como se puedan imaginar. Cada uno de ellos tendrá su propio lenguaje ubicuo aunque algunos de los términos entre los distintos contextos delimitados que componen el sistema se puedan sobreponer.

Los retos de aplicar el DDD


Los principales retos son:

  • Involucrar a los expertos del dominio durante todo el proceso del desarrollo del negocio.
  • La inversión de tiempo y esfuerzo necesarios para crear la ubicuidad del lenguaje.
  • Cambiar la manera en la que los desarrolladores piensan en las soluciones del dominio.

Uno de los mayores retos es concienciar a los expertos de negocio de su implicación durante el desarrollo.

Otro gran reto es pensar sobre el dominio y, junto con la ayuda de los expertos de negocio, definir el lenguaje ubicuo así como los contextos delimitados de manera que el conocimiento del dominio sea lo más completo posible.

El último gran reto es cambiar la manera en la que piensan los desarrolladores ya que estos piensan desde la perspectiva técnica. No es que pensar técnicamente sea algo malo pero en el momento en que hay que comunicarse con gente de otros ámbitos es mejor adaptarse y pensar un poco menos técnicamente.

Conclusiones


Durante este capítulo se ha visto el enfoque del DDD para el desarrollo de software y cómo afecta sobre el diseño del software.

Se ha visto también el esfuerzo que se requiere a la hora de involucrar a los expertos de negocio así como a la hora de crear lenguaje ubicuo y los contextos delimitados.

El DDD se utiliza en partes en las que la complejidad es elevada con el objetivo de modelarlo de la forma más sencilla posible.

También se han visto los principales retos a los que un equipo se enfrentará.