Introducción

Antes de nada, sería pertinente comenzar por el por qué del grupo. Recientemente nos planteamos la certificación de Symfony para los desarrolladores de nuestra empresa, y en la documentación de los pasos a seguir, vimos que desde la página de academia de Sensiolabs tenían con frecuencia cursos y talleres de preparación, en Francia, Londres y Alemania. Cuando les preguntamos sobre la posibilidad de realizar la formación aquí en España al igual que en otros países, la respuesta que obtuvimos es que no hay tanta gente que lo solicite, por lo que no se lo plantean.

Queremos conseguir que todos los desarrolladores de Symfony que lo deseemos tengamos la posibilidad de tener un espacio en el que discutir inquietudes, apoyarnos y mejorar, sin tener que esperar a grandes eventos anuales como el deSymfony o Codemotion para ello, y por esas razones, creamos el grupo de Symfony.

Un poco de contexto

El pasado jueves tuvimos la suerte de poder organizar nuestro primer meetup, «Los retos de la comunidad Symfony«, y desde aquí quiero agradecerles a todos los asistentes que nos brindaron su tiempo. Desde el principio queríamos desmarcarnos de la clásica master class, que aunque no tiene nada de malo, no se ajustaba tanto a nuestra idea de generar comunidad en torno a Symfony, queríamos romper el hielo entre los participantes (que no oyentes), y queríamos debate.

 

Los retos de la comunidad Symfony

Como adelantaba antes, queríamos que el meetup fuera algo más comunicativo, que todos los presentes aportasen su visión, mostrasen sus inquietudes y pudieran ser ayudados. Pensamos usar Lean Coffee como método para obtener, priorizar y tratar temas de conversación que todos deseáramos discutir.

Para el que desconozca cómo funciona lean coffee, está dividido en tres grandes bloques de los que hicimos uso de la siguiente manera:

  • Obtención de temas: el primer paso era saber los temas sobre los que querían hablar los participantes. Para ello, planteamos las preguntas «¿Qué quiero aprender?», «¿Qué puedo aportar?», «Dudas existenciales». Repartimos una serie de post-its sobre los que escribir los temas que quisieran tratar y que posteriormente se colocaron bajo cada pregunta en un muro. Para tener mejor visibilidad de todo, dedicamos unos instantes en agrupar los temas similares o los que directamente eran iguales.
  • Priorización: una vez teníamos todos los temas, los priorizamos para hablar sobre los que pudiéramos dentro del tiempo que teníamos disponible, repartimos entre cada uno 5 puntos que usarían para votar los temas que les resultaran más interesantes, y de esa manera, ordenarlos y detectar los prioritarios.
  • Discusión: establecimos un timebox de 5 minutos para hablar por tema, llegando a la posibilidad de prorrogarlos con una votación hasta que todos pensásemos que el tema no daba más de sí.

Temas tratados

Tras realizar los primeros dos pasos del Lean Coffee, se nos quedó el siguiente muro con los temas que trataríamos en la siguiente hora:

Muro de temas a tratar sacados en el Lean Coffee

Muro del Lean Coffee

Como podéis ver, uno de las grandes preocupaciones que asaltaban a los participantes es la gestión de los assets del frontal de nuestras aplicaciones, cómo hacemos uso de Gulp y/o Webpack Encore. Este tema se llevo gran parte del tiempo asignado del meetup.

Otro tema que tratamos fueron sobre la forma en la que cada uno realizaba la subida a producción de los assets, el debate estaba en generarlos en local y copiarlos arriba, o generarlos directamente arriba. Cada uno defendió sus ventajas e inconvenientes dependiendo de lo que acostumbra a hacer.

Siguiendo con los frontales de nuestras aplicación, surgió la visión de cómo Symfony estaba alejándose de la alimentación del frontal para centrarse en el lado back de las aplicaciones, dando paso así a los clientes desarrollados con frameworks javascripts como React, Angular o Vue. Dedicamos un rato a discutir nuestras experiencias con cada uno, cómo realizamos las comunicaciones entre cada parte, y el manejo de datos sensibles de usuarios.

El último tema que nos dio tiempo a tratar fue el de la gestión de formularios en Symfony, la validación, creación de Constrains. Cada uno expusimos cómo trabajamos con los formularios.

Se quedaron fuera temas interesantes como Certificación, los cambios que se acercan con Symfony 4 o testing, uso de servicios para la lógica de la aplicación frente a custom events.

Cierre

Una vez más, me gustaría desde aquí mandar un saludo a todas las personas que quisieron y pudieron venir, esperamos que les resultase una experiencia enriquecedora y quieran repetir en el próximo. Por otro lado, a todos los que os interese apuntaros al grupo y estar al tanto de los próximos eventos que organicemos, dejo el enlace al registro en el grupo de Meetup.

Esta es la narración de una historia de amor. Breve, intensa y que terminó de forma brusca, contra un muro.

Todo empezó con un encuentro tan casual como inevitable.

Por un lado un estudio digital buscando una herramienta que hiciese el desarrollo de aplicaciones web más eficaz, fiable y escalabale, y que abriese la puerta a exportar ese conocimiento para generar aplicaciones móviles.

Por otro, con uno de tantos frameworks de JavaScript ofreciéndose cual sandía abierta en la red de redes (saludos a los señores periodistas digitales de los mass media).

 

Qué inocente parece, tan sencillo, pulcro y fácil de instalar.

Dentro de las opciones disponibles, estaban los nombres habituales: Angular, React, Ember, Backbone

Pero uno llevaba desde hacía un tiempo llamando poderosamente la atención de todo aquel que se adentraba en este mundo: Vue.

Sus virtudes eran obvias: ligereza, rapidez, versatilidad y sobre todo una curva de aprendizaje de lo más agradable, en la que con un conocimiento previo de HTML/CSS/JavaScript podías obtener resultados muy vistosos de forma casi inmediata.

Para un estudio modesto, en el que la inversión en I+D no puede competir con la de grandes corporaciones al estilo Weyland-Yutani, era una verdadera tentación, imposible de resistir.

El tiempo es dinero, y si un 89% de los desarrolladores decían en 2016 estar tan satisfechos con él como para volver a usarlo, no había más que pensar.

Así, la relación nació llena de ilusión, con un primer acercamiento a la reescritura del Rand-o-matic muy rápida y vistosa.

Versión 0.1 del Rand-o-matic Vueizado. Jusqu’ici tout va bien.

El Tocstrap, como buen amigo, echó una mano en ello, y todo parecía ir sobre ruedas, pero ya sabemos que al principio la pasión lo tapa todo.

El problema vino, como tantas otras veces, con una tercera persona.

Llegó la hora del cambio, de dar el siguiente paso y comprometerse a ser capaces de hacer aplicaciones móviles.

Deberíamos haber empezado a sospechar cuando la elección del framework que debía ayudarnos a conseguirlo no se mostraba con claridad ¿Weex? ¿Cordova? ¿Phonegap? ¿Quasar? ¿Framework7? ¿Ionic? Cada uno tenías sus ventajas e inconvenientes, algunos ya los conocíamos y no nos convencían, otros estaban en un estado de desarrollo demasiado temprano, otros no estaban pensados para funcionar con Vue sino con Angular, otros eran de Adobe…

Con las dudas propias de quien da un like en Tinder a alguien que solo tiene una foto, optamos por Weex. Parecía la opción menos mala dentro de las posibles.

Weex.

Recordad ese nombre. Anotadlo junto al de Summer.

Los problemas empezaron a manifestarse desde el principio, una vez metido entre medias de la relación.

El hecho de tratar de hacerlo funcionar en un entorno Windows no hizo sino agravarlos ¿Pero qué clase de futuro podía esperarnos si no era capaz de resistir una prueba tan dura? Variables de entorno, actualización de Node, instalación de Android Studio, JDK y drivers del dispositivo, añadido de la plataforma de Android… todo lo que en el ecosistema Web App había sido fluidez y avance, aquí se volvía barricadas, retrocesos y desesperación.

Cuando creíamos haber logrado por fin deshacer el nudo, se volvía a enmarañar y había que volver a empezar.

Y para colmo, al ser un proyecto de Alibaba y estar poco extendido aún, gran parte de las dudas había que resolverlas en chino ¿Os imagináis Stack Overflow en chino en vuestro día a día? Intentadlo.

Gracias chicos, pruebo lo que decís y os cuento

El golpe definitivo vino cuando tuvimos que añadir estilos: instalación de paquetes de node (style-loader, css-loader), intentos de importación de ficheros externos, como si de un componente se tratase, intentos de carga asociados a <style>, intentos de carga de todo nuestro Tocstrap incrustado inline. Nada, que no había forma de que aquello cogiese los estilos. Estábamos intentando forzar algo que había nacido fracasado.

Y la culpa fue nuestra, por fiarnos. Por no leer la documentación y ver esto:

The CSS standard may support a lot of selectors, but now weex only support single-class selector.

The CSS standard can support many types of length units, but now weex only support pixel, and the px unit could be ignored, you can write number directly.

The styles of Weex cannot be inherited to children elements, this is different to the CSS standard, such as color and font-size.

The CSS standard contains a lot of styles, but weex only sopport few styles which include layouts such as box model, flexbox, positions.

¿En serio?

¿Y nos dices ahora que estás casado y tienes hijos?

¿De verdad no crees que es algo que deberías poner en tu página home para que, si empiezo algo contigo, sepa a que atenerme?

No sé, algo así como en letras mayúsculas, a tamaño 70 y en #f00. Está bien, no podíamos echarle la culpar, la información estaba ahí, algo escondida, pero estaba. Y nuestra obligación era habernos informado antes de tirarnos a la piscina del I+D.

No era momento de buscar culpables, sino soluciones.

Bien, bien… lo que se dice bien… ahora mismo no me caes mucho

Así que hicimos lo que hemos aprendido en tantas películas: cortar.

Asumir que aquello no iba a ningún lado, que no estábamos hechos el uno para el otro. Ta vez en dos años hubiese tenido más sentido, pero no ahora, nos habíamos equivocado con el momento.

Hicimos limpieza, nos quedamos con la parte de Vue que aún podía salvarse para hacer Web Apps de forma rápida y ligera, y nos pusimos a buscar otra pareja con la que seguir recorriendo al camino.

¿Cuál fue nuestra elección? Solo adelantaremos que, como decía Hitchcock, «en caso de duda lo mejor es refugiarse en lo conocido«.

 

 

 

 

 

Uno de los grandes “problemas” que nos encontramos en Elemento115 a la hora de hacer despliegues rápidos en un corto lapso de tiempo es, precisamente, cómo mostrar estos cambios al usuario final. Me explico.

Nuestro flujo de trabajo nos permite hacer cambios rápidos de diseño y funcionalidad en la parte cliente, por lo que podemos llegar a desplegar una aplicación bastantes veces al día. ¿Nuestra némesis? La caché. Ese elemento que ayuda tanto a que nuestros desarrollos carguen a una velocidad óptima también provoca que el usuario no vea los cambios de manera inmediata.

Para solucionarlo tenemos varias opciones, como dejar los archivos servidos expiren en tiempos relativamente cortos (en nuestro caso debería ser de horas) o forzar el de nuevo la bajada haciendo que expire manualmente. Ninguna de estas opciones nos convence. Hasta Symfony 2.8 utilizábamos Assetic para la gestión de assets. Este componente estaba integrado en Symfony, era fácil de utilizar y además nos solucionaba este problema con un sistema simple, el versionado de archivos. Pero, y siempre hay un pero, Assetic pasó a estar deprecado en Symfony 2.8.

 

Gulp al rescate.

¿Cómo afrontamos esto? Fácil, nos subimos al barco de Gulp. La integración con Symfony fue sencilla y además ganamos tiempo a la hora de hacer los despliegues gracias a que Gulp resultaba ser más rápido que Assetic a la hora de procesar los assets. Pero (otra vez) perdimos la facilidad con la que versionabamos los archivos, ya que con Assetic solo era necesario cambiar el número de versión en un archivo de configuración.

No íbamos a hacer de esto un drama, así que nos pusimos manos a la obra para solucionar el tema del versionado de archivos de la manera más limpia y automatizada posible. Queríamos que, cada vez que un archivo, ya sea CSS o JS, fuera modificado, se actualizase la versión de este para servir el nuevo contenido a los usuarios de manera inmediata. Para ello integramos gulp-rev, un paquete de Gulp que se encarga de añadir un hash a los archivos que necesitamos versionar. Un ejemplo práctico con archivos Sass/Css:


gulp.task('public-clean-assets', function() {
    return gulp.src(['web/public/css/*.css', 'web/public/**/*.js'], {read: false})
        .pipe(clean({force: true}));
});

gulp.task('public-sass', function() {
    return gulp.src('app/Resources/front/public/scss/*.scss')
        .pipe(sass({includePaths: ['app/Resources/front/public/scss/modules']}))
        .pipe(gulp.dest('app/Resources/front/public/css'))
        .pipe(notify({message: 'PUBLIC SASS OK', onLast: true}));
});
gulp.task('public-styles', ['public-clean-assets', 'public-sass'], function() {
    return gulp.src('app/Resources/front/public/css/**/*.css')
        .pipe(cleancss())
        .pipe(rename({suffix: '.min'}))
	.pipe(rev())
        .pipe(gulp.dest('web/public/css'))
	.pipe(rev.manifest('web/rev-manifest.json', {
            merge: true
        }))
	.pipe(gulp.dest('.'))
        .pipe(notify({message: 'PUBLIC CSS OK', onLast: true}));
});

Aquí actúan básicamente tres tareas de Gulp.

  • Con public-clean-assets limpiamos las carpetas de assets públicos, así no acumulamos un gran numero de archivos sin utilizar.
  • public-sass se encarga de procesar todos los archivos Sass de la aplicación.
  • public-styles se encarga de:
    • “Minificar” el archivo resultante de procesar los archivos Sass.
    • Añadir el sufijo “.min” una vez minificado.
    • Añadir el hash de versión.
    • Mover el archivo resultante a la carpeta pública desde donde se sirve.
    • Añadir una entrada en el rev-manifest.json con el nombre del archivo original y el resultante.

Vale, ya tenemos los archivos listos para servir, ¿como sabe Symfony qué archivos servir?

 

Servir la versión correcta con TwigExtensions.

Vamos a aprovechar el archivo rev-manifest.json para servir los assets correctos. En el archivo rev-manifest.json tenemos, por ejemplo, el siguiente contenido:


{
  "jquery-3-2-1.min.js": "jquery-3-2-1-c9f5aeeca3.min.js",
  "jquery-ui.min.js": "jquery-ui-fdf4d9013c.min.js",
  "main.min.css": "main-6ca53126cb.min.css",
  "main.min.js": "main-32fc16b6cd.min.js"
}

Aquí tenemos la relación entre el archivo que queremos utilizar (main.min.css por ejemplo) y el nombre versionado del archivo (main-32fc16b6cd.min.js). Para hacerlo de manera automática vamos a crear una extensión de Twig que realice este proceso por nosotros:



namespace AppBundle\Twig; 

/** 
 * AssetVersionExtension 
 */ 
class AssetVersionExtension extends \Twig_Extension 
{ 
    private $rootDir; 

    /** 
     * Constructor 
     * 
     * @param string $rootDir
     * @param string $cssDir
     * @param string $jsDir 
     * @param string $pluginsDir 
     */ 
    public function __construct($rootDir, $cssDir, $jsDir, $pluginsDir)
    { 
        $this->rootDir = $rootDir;
        $this->css = $cssDir;
        $this->js = $jsDir;
        $this->plugins = $pluginsDir;
    }

    /**
     * @return array
     */
    public function getFilters()
    {
        return array(
            new \Twig_SimpleFilter('assetVersion', [$this, 'getAssetVersion']),
        );
    }

    /**
     * Retrives the hashed version of the file
     *
     * @param string $filename
     * @param string $fileType  Should match js or css property
     * @param string $subfolder If the file is in a subdirectory it must by especified
     *
     * @return string
     */
    public function getAssetVersion($filename, $fileType, $subfolder = '')
    {
        $manifestPath = $this->rootDir . '/../web/rev-manifest.json';
        if (!file_exists($manifestPath)) {
            throw new \Exception(sprintf('Cannot find manifest file: "%s"', $manifestPath));
        }

        $paths = json_decode(file_get_contents($manifestPath), true);

        if (!isset($paths[$filename])) {
            throw new \Exception(sprintf('There is no file "%s" in the version manifest!', $filename));
        }

        return $this->{$fileType} . $subfolder .  $paths[$filename];
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'asset_version_extension';
    }
}

Declaración del servicio en services.yml:


...
app.twig.assets.version.extension:
    class: AppBundle\Twig\AssetVersionExtension
    arguments: ['%kernel.root_dir%', 'public/css/', 'public/js/', 'public/js/vendor/']
    tags:
        - { name: twig.extension }
...

¿Como funciona la extensión? Básicamente se le pasa como parámetros el nombre original del archivo y el tipo de archivo. Con esto, se encarga de leer desde el rev-manifest.json cual es el archivo correcto a utilizar.

Un ejemplo de uso:


...
< link rel="stylesheet" href="{{ asset('main.min.css'|assetVersion('css')) }}" />
...

Con esto, ya tenemos automatizado el versionado de los assets, además de servir siempre el archivo correspondiente sin necesidad de cambiar ningún tipo de configuración en los despliegues.

Un apunte sobre Gulp y la «sincronicidad».

Gulp, al ser una herramienta escrita puramente en JavaScript, ejecuta las tareas de manera completamente asíncrona. Debido a este comportamiento, es posible que intente hacer un versionado de archivos que aún no existen, por ejemplo cuando aún no se ha terminado de procesar los ficheros Sass.

Esto es fácil de corregir, podemos «forzar» a que Gulp actúe de manera síncrona. Tan solo es necesario pasar como segundo parámetro a la función gulp.task que lo requiera un array de tareas a las que debe esperar antes de ejecutarse. En el caso de la tarea public-styles, esta no se ejecuta hasta que public-clean-assets y public-sass han terminado.

He aquí la gran pregunta.

Respuesta corta: porque tenemos un Transtorno Obsesivo Compulsivo. De ahí el nombre del framework. Tocstrap. Ríete tú de Sterling Cooper.

Respuesta larga: porque nos hacía falta una herramienta front con la que afrontar nuestros proyectos, que nos hiciese más rápidos, autónomos y eficaces, y evitase malgastar tiempo en tareas repetitivas de un proyecto a otro. Y todo ello sin generar dependencias de terceras partes, o las mínimas posibles, manteniendo el máximo control sobre el código.

Es decir, un TOC de manual.

Home de Tocstrap

Sí, sí, van en serio, le hemos puesto ese nombre

Así que, con las suficientes referencias a nuestras espaldas que dan el ya maduro recorrido de Elemento115, y que nos permiten saber qué necesitamos como equipo y qué nos haría mejores, nos decidimos a comenzar nuestro propio framework de CSS y JavaScript.

La forma de abordarlo es sencilla: siguiendo las ideas del Atomic Design hemos creado una conjunto de componentes aislados entre sí que nos permiten afrontar de forma automática la creación de cualquier elemento que nos podamos encontrar en un proyecto, así como dotarle de comportamiento. Y todo ello documentado en unas guías de estilo dinámicas, accesibles a través de una URL propia, y que cargan los mismos ficheros que el resto del proyecto. De esta forma nos aseguramos de la autoactualización de la guía de estilo, ya que al modificar el componente del proyecto se modifica automáticamente su homólogo en la guía de estilo.

A todo ello hay que añadir un sistema de grid, basado en el de Bootstrap, que permite a los desarrolladores una buena dosis de autonomía al crear plantillas, sin tener que depender del departamento de Front-end. No nos hemos atrevido aún con el CSS Grid, pero sí con Flexbox, y en lugar de las 12 columnas habituales nos hemos ido hasta las 20, que da más margen para afinar y da divisiones enteras del 100%, y no números periódicos puros en los que uno no puede confiar. Otra vez el TOC.

Columnas del sistema de grid de Tocstrap

Nuestro grid en todo su esplendor

También hemos aportado las ventajas que da usar SASS y Gulp. Tenemos un fichero de settings que configuramos al inicio del proyecto y que nos permite establecer de forma cómoda y rápìda aspectos tan dispares como:

  • Colores corporativos
  • Anchos de los contenedores principales
  • Espacio de los gutters del grid
  • Tamaños y tipografías de los textos
  • Puntos de corte de las media queries
  • Velocidad de las transiciones CSS

De este fichero beben todos los componentes del framework, así que si a mitad del proyecto el cliente quiere cambiar un rojo por un verde, tardamos unos 10″ en hacerlo (y 9″ son de abrir el fichero y arrancar el Gulp).

Aspecto del fichero de settings de SASS

Todas estas cosas podemos modificar fácilemente

El resto de elementos CSS del framework se reparten en módulos de SASS que agrupan aspectos similares, tales como layout, texts, forms… Desde la hoja de estilos principal cargamos dichos módulos, que junto al reset CSS y a los mixins de SASS, nos dejan en una posición de inicio estupenda para arrancar el proyecto con mucho tyrabajo ya hecho.

En cuanto al JavaScript, reunidas todas las funcionalidades en un único fichero y encapsuladas en objetos aislados entre sí, nos permite una inicialización muy sencilla basada en unas convenciones de sintaxis HTML para cada componente y una llamada al método init() correspondiente. No hay, por tanto, que preocuparse por el comportamiento: el framework hace el trabajo por ti.

Aspecto del fichero principal de JavaScript

El init() es nuestro amigo

Esto que hemos hecho no es más que el arranque del camino. Nos queda muchísimo por recorrer, muchas cosas que añadir, unas cuantas que modificar y más de una que eliminar. Tal vez cambiemos Gulp por Webpack o usemos ambos, puede que dejemos de lado jQuery por ES6, incorporaremos Grid CSS en cuanto podamos, y una lista interminable de cambios que ahora ni podemos intuir. Pero la idea básica, el esqueleto sobre el que construir, seguirá siendo el mismo: un único framework para gestionarlos a todos.

La semana pasada llegaba, de la mano de Firefox 52, la primera versión definitiva en producción de Grid Layout. Dos días más tarde le seguía Chrome 57, y es de esperar que Safari lo haga en breve, incluso han publicado ya un artículo en su blog con una introducción a Grid. A Edge de momento no se le espera, salvo soportando la anterior especificación.

La importancia, posibilidades e impacto que tendrá en la forma de trabajar, la poco habitual simultaneidad en el soporte de los principales navegadores, así como el largo y tortuoso camino seguido hasta llegar aquí, hacen de este lanzamiento uno de los eventos más importantes en la historia reciente de CSS.

Pese a que no han faltado los primeros bugs en Chrome, con extraño diagnóstico incluído, parece el momento adecuado para leer el estupendo tutorial de Rachel Andrew, esta guía tan completa o tal vez prefiramos empezar con el sencillo inicio que propone CSS-Tricks, en donde nos encotramos una cita de Jen Simmons que convendría no perder de vista:

We need to explore CSS Grid until we understand what it wants to do, what it can be forced into doing, and what it refuses to do. Many designers may not ever learn to code CSS, but you need to understand CSS well enough to understand our artistic medium.

No sería la primera vez que la llegada de una nueva tecnología, o incluso una forma totalmente nueva de abordar el trabajo, nos lleva a forzar los límites y caer en un uso incorrecto de la misma. Leamos, aprendamos, pongamos en práctica y disfrutemos. Se nos acaba de abrir un nuevo horizonte 🙂