Creación de aplicaciones React The Agile Way

React se ha transformado en los últimos tiempos en una de las librerías más empleadas en el momento de encarar el inconveniente de la comunicación con el DOM. Merced al trabajo de muchos desarrolladores y divulgadores, existen multitud de recursos tanto gratis como de pago que hacen que aprender React sea una labor parcialmente fácil, con lo que no nos centraremos tanto en el manejo de propiedades o bien en la administración del estado en React, sino más bien más en su empleo como solución general en un contexto Agile.

Este artículo no va de porqué React y no Angular cuatro o bien VueJS. Si aguardabas un flame a este respecto siento desilusionarte. Este artículo se centra en como hacer que una herramienta como React se alinee con nuestra forma de enfocar el desarrollo de software.

La iteración 0

Toda vez que comenzamos un nuevo proyecto debemos crear la estructura del mismo y preparar las herramientas precisas para ir agregando funcionalidad de forma progresiva haciéndola llegar a producción de la manera más veloz y eficaz. Esta construcción incial en la iteración 0, se conoce como Walking Skeleton y está descrita en detalle en el Growing Object-Oriented Software, Guided by Tests, siendo aparte de vital relevancia para asegurar una adecuada evolución del proyecto. Si no estáis familiarizados con el término, la idea primordial es procurar que la primera historia de usuario que incorporemos en el sistema, por muy mínima que sea, actue como una bala trazadora obligándonos a acotar todo nuestro sistema, construcción, despliegue y puesta en producción desde el comienzo. De esta manera, toda vez que acabemos una historia de usuario, esta va a poder terminar en producción de una manera fácil y predecible al haber incorporado desde el comienzo todo el ciclo completo de construcción y despliegue.

En el caso de React y empezando por la creación del proyecto, podemos producir esta estructura inicial a través de una utilidad que tiene por nombre create-react-aplicación. Con create-react-aplicación podemos administrar un proyecto React sin lidiar de manera directa con las complejidades del tooling de nueva generación que envuelve a la mayor parte de proyectos JavaScripts actuales. Un pequeño averno que debes aprender a supervisar dominando Babel, NPM, Webpack y otros amigos con los que sostener una relación de amor/odio.

Con create-react-aplicación tenemos gratis:

Babel: React, JSX y ES6.
Chequeo de tipos con Flow.
Linting con ESLint.
Webpack: Dev server soporte para los loaders de CSS y también imágenes.
Testing con Jest.
Autoprefixer.
Build script para generación de versiones de producción, con imágenes optimados y soporte para Source Maps.
Offline-first service worker y webapp manifest para Progressive Web Aplicaciones.
Si no te agrada tanta magia negra, siempre y en todo momento puedes ejecutar el comando npm run eject y hacer explícita la configuración usada (toda la config se guarda en la raíz de tu proyecto), pudiendo de esta forma amoldar tu aplicación a cualquier configuración no soportada en un inicio por create-react-aplicación.

Como es lógico, a la parte usuario debemos incorporar las llamadas a nuestro backend que expondrá la funcionalidad deseada como servicio. En todo caso, sencillamente recordaros que para poder conectar con la una parte del servidor sin tener inconvenientes de CORS, podemos emplear la opción de proxy de nuestro servidor de desarrollo.

Empezando la casa por las historias de usuario

Cualquier funcionalidad en un proyecto Agile nace merced a su formalización como historia de usuario. Si bien todo esto lo explica Mike Cohn mucho mejor que , me agradaría centrarme en un aspecto que para mi es clave en su escritura y que cada vez veo a más equipos obviar en el momento de crear una buena historia de usuario: El Definition of Done o bien DoD para los amigos.

Sin el DoD, no tenemos una forma clara de contrastar que las esperanzas de la historia de usuario se han satisfecho una vez finalizada. Es la descripción formal, sistematizada y reproducible del aumento de valor aportado y, como tal, debe asistirnos a guiar nuestro desarrollo dirigido por pruebas.

No se que debo testar es una de la aseveraciones que más acostumbras a percibir cuando alguien está empezando a introducirse a XP (ojo que XP no es un sistema operativo obsoleto que incluso vaga por el planeta, sino más bien un conjunto de prácticas técnicas sintetizadas por Kent Bech en Extreme Programming Explained).

¿Como iniciar entonces mis primeras pruebas? Puesto que si proseguimos una aproximación de fuera cara dentro (outside-in TDD), el primer test del que vamos a partir va a ser un test de aceptación construido desde la definición del DoD que nuestro Product Owner ha escrito para nosotros. Si todo esto te suena un tanto a chino y deseas saber más sobre los tests de aceptación o bien de testing por lo general, puedes echarle un ojo a Test-Driven Development by Example de Kent Beck o bien Growing Object-Oriented Software, Guided by Tests de Steve Freeman.

Centrando un tanto más el tema, nuestro objetivo es que cada funcionalidad que se defina en mi backlog en forma de historia de usuario tenga su DoD y pueda dar sitio a un test de aceptación que guíe el desarrollo. Para este primer test de aceptación, no utilizamos el término de historia de usuario ejecutable que podemos ver en Cucumber en su definición más BDD y/o ATDD, sino es el equipo técnico el que escribe estos tests desde el DoD y los automatiza a fin de que se ejecuten a través del navegador (si bien empezamos hace ya un tiempo con PhantomJS, ahora pasamos a Google Chrome headless y desde hace nada siguiendo muy de cerca el trabajo tras Google Chrome Puppeteer).

Si ya conoces bien la comunidad JavaScript, vas a saber que existen mil millones de frameworks para cada cosa, y el tema del testing no es una salvedad. Desde la base definida por Selenium y WebDriver podemos hallar una muy, muy amplia gama de opciones con la que deberemos lidiar ya antes de poder poner a marchar nuestro primer test de aceptación, conque si las opciones escogidas para este caso de ejemplo no te persuaden, deja de preocuparte, hay mucho donde seleccionar!!!

Como curiosidad, comentar que empleamos NightWatch para lanzar este género de pruebas y que, para eludir la debilidad de los tests por cambios en la interfaz, los puntos del UI son accionados a través de una abstracción que definimos sobre los componentes siguiendo el patrón Page Object.

Siguiendo nuestro enfoque dirigido por las pruebas de aceptación, deberíamos tener el test fallando y en colorado y el Page Object pertinente definido mas sin posibilidad de interactuar con ningún componente de la interfaz. Estamos en el buen camino!! Prosigamos puesto que adelante :)

Tests de integración de componentes

Con un test de aceptación en colorado que sostendremos a lo largo del tiempo que tardemos en satisfacer el DoD de la historia de usuario, es hora de empezar a incorporar la funcionalidad deseada a través de la interacción de diferentes componentes dentro de la interfaz.

Es ahora instante cuando herramientas como enzyme, merced al shallow rendering que deja React, nos dejarán ir definiendo como se deben comportar en lo que se refiere a interacción y en lo que se refiere a definición nuestros componentes.

Antes de seguir, agregamos las dependencias precisas a nuestro proyecto, teniendo presente que, si hemos utilizado create-react-aplicación como hemos comentado previamente, Jest va a ser el framework de test que vamos a tener como base para la ejecución de los tests.

npm install –save-dev chai enzyme react-test-renderer

Una vez todo instalado, ya podemos crear un test en nuestro proyecto.

Si bien se puede hacer de muchas formas, Jest aguanta la definición de directorios __tests__ en los diferentes niveles de nuestra estructura de código, de manera que podemos dejar en estos directorios las clases de test y los recursos que empleen en ellas.

Como un ejemplo, podemos ver este test que prueba un componente que lista películas de StarWars utilizando un Page Object:

jest.mock('../Repository');

import React from 'react';
import undefined from 'enzyme';

import Aplicación from '../../App';
import Largometrajes from '../Films';

const FILM_TITLES = [
'The Phantom Menace',
'Attack of the Clones',
'Revenge of the Sith',
'A New Hope',
'The Empire Strikes Back',
'Return of the Jedi',
'The Force Awakens'
];

const FILM_EPISODES = FILM_TITLES.map((title, index) => index 1);
const NUMBER_OF_FILMS = FILM_TITLES.length;

describe('Films', () => undefined);

Como podemos ver en la primera línea de código del ejemplo, se usa un doble de test o bien mock, de manera que los datos no se cargan verdaderamente del origen HTTP, sino se definen para servir ciertas fixtures en un directorio singular que en Jest lleva por nombre __mocks__.

Así, solo nos quedaría echar una ojeada al Page Object empleado para el acceso a la estructura de películas:

export default class Largometrajes undefined

Y, como no, acá tenemos el componente principal:

import React, undefined from 'react';

import repository from './Repository';

export default class FilmsPanel extends Component undefined

Una vez añadido todo el código de test preciso a nuestro proyecto, deberemos lanzar el comando npm test para poder ver como la ejecución de las pruebas se queda en modo watch, aguardando cambios por nuestra parte:

Con este ciclo que hemos abierto, solo debemos proseguir iterando en estas definiciones hasta el momento en que todos y cada uno de los requisitos del DoD se hayan satisfecho y el test de aceptación general pase al fin de colorado a verde. Well done!!! :)

Conclusión

El framework primordial de elección es solo una parte mínima del conjunto de resoluciones que debemos llegar a tomar para diseñar un proceso de construcción escalable y de calidad. Prácticas como el testing, la integración continua y la adecuada definición de historias de usuario tienen un peso intrínseco interminablemente mayor que ser