2017/10/18

La solución imperfecta


¿Por qué el mundo esta lleno de soluciones imperfectas?

Porque la solución depende del contexto.

Digamos que tienes cinco minutos para ordenar la salida de un sistema y un plugin ya listo que lo hace.

El algoritmo hace una ordenación simple tipo burbuja pero cumple con lo que necesitamos.

Si tuvieras un par de horas, quizas podrías hacer desde cero un plugin con el mejor algoritmo de ordenación posible.

Si tuvieras una hora, quizás podrías modificar este plugin y mejorar el algoritmo de ordenación.

Si tuvieras media hora, quizás podrías buscar si alguien más ha hecho ese plugin.

Pero tienes cinco minutos.

Poner este plugin te llevará un minuto, un pequeño test otro minuto, y ya estás gastando tiempo en analizar las alternativas. Alternativas que requieren más tiempo del que dispones. Y todas con un quizás. No existen. Sólo existe este plugin imperfecto, aquí y ahora.

No se trata de usar las respuestas de un libro de texto. Se trata de la vida real, retándote a hacer lo mejor que puedas con lo que tienes disponible en este momento.

Lo eliges. No es la respuesta perfecta, pero es la solución. En este contexto, es la respuesta.

Te gustaría que alguien te comprenda por usar una respuesta no optima.

Ahora te parece tan obvio.

Realizar una solución imperfecta es mejor que una respuesta perfecta que no se puede realizar.

Lo aceptas, y sigues adelante. Quizás en la siguiente iteración la puedas mejorar.

También es un quizás. Pero es es un quizás con algo corriendo.


Imagen de http://news.nationalgeographic.com/content/dam/news/2017/04/27/frog-gallery/01-frog-day-gallery.jpg

2017/08/28

El problema de la sobrecarga innecesaria

Problemas reales

Pienso que resolver problemas es una cuestión de prueba y error.

Que no es como te lo enseñan en la escuela, donde aprendes a copiar soluciones de los libros de texto.

Resolver un problema es como andar a tientas por una habitación a oscuras, tratando de llegar a la puerta.

Lo que te dan los libros de texto son como escenarios prefabricados de juegos con finales conocidos. Llenos de cosas que los maestros han puesto y con rutas de solución que ellos ya conocen.

En los problemas reales, puede haber más de una ruta de solución. O ninguna.

También encontraras montones de cosas que te sirven mezcladas con cosas innecesarias. Y necesitarás aprender a notar cuál es cuál.

Enfrentarte a problemas reales despierta cierto sentido. Aprendes a escuchar al problema. Aprendes a buscar dentro de ti. Aprendes a construir caminos.

Patrones

Conforme vas resolviendo problemas, te das cuenta que se repiten ciertos patrones para solucionarlos.

Identificar estos patrones ayuda a catalogar las soluciones y facilitar su reutilización.

Por ejemplo:
  • Qué tal si divido el problema en partes. Si varias de esas partes me son familiares, podría avanzar por allí.
  • Qué tal si solo considero algunos detalles (eso se llama abstracción). A lo mejor veo más claro en esa versión simplicada.
Ayuda dividir el trabajo web en partes separadas.

También ayuda quitar de en medio una problemática innecesaria.

MVC

Modelo-Vista-Controlador es un patrón de desarrollo web que divide el trabajo en tres areas:
  • Vista: la interfaz de usuario, HTML, CSS, Javascript
  • Modelo: los datos que la Vista mostrará
  • Controlador: el que orquesta las actuaciones de la Vista y el Modelo
Se trata del patrón Qué tal si divido el problema en partes. La idea es concentrarse en cierto aspecto del desarrollo para simplificar el trabajo.

Componentes

El desarrollo de un site o una aplicación web, no es una tarea definida. Es un problema cuyas tareas hay que ir descubriendo en el camino, durante sucesivas iteraciones. No es ir de la A a la Z y ya. Es ir por las letras de un mensaje desconocido, fallando y acertando mientras se va haciendo más claro.

Para iterar con agilidad, necesitamos poder hacer cambios con facilidad.

¿Ayuda MVC en esto?

MVC ayuda a enfocarse en cierto aspecto del problema y a organizar todas las cosas en esas tres grandes areas. Pero esa virtud también tiene su inconveniente. La navegación por el mar de las posibilidades se vuelve muy, muy pesada. Cierto que sabemos donde queda cada cosa y eso es muy bueno. Pero, por otro lado, la implementación de cada idea se vuelve engorrosa.

Imaginamos las cosas naturalmente como componentes, pero en MVC cada solución o variante que imaginemos tiene que ser dividida en tres partes antes de poder implementarlas. Es un ejercicio constante de traducción entre lo que imaginas y lo que haces para producirlo.

Está bien, pero quizás podría ser mejor.

Entran los componentes.

¿Qué tal si dividimos las cosas no por areas M, V, C, sino por funcionalidades, por componentes?

Es parecido a decir, que tal si en lugar de tener carpetas css, js, images, tenemos varias carpetas home, contact, menu, header, product, etc, cada una representando una funcionalidad o conteniendo otras carpetas de funcionalidades.

Confusiones papistas

Más papista que el Papa, dice un refrán. En algunos proyectos hay personas que adoptan esta actitud de defender algo como cierto porque sí, porque así es.

Gente que toma MVC como una biblia o estresa al equipo que obvia una ceremonia del scrum.

Lo importante es honrar el por qué de las cosas. MVC busca claridad. Scrum busca bienestar del equipo.

¿Los componenentes podrían hacerlo mejor? ¿Podríamos sentirnos menos estresados? Probemos.

El problema en el Frontend

Este es más o menos el flujo de trabajo que se sigue al desarrollar web:
  1. Se propone un diseño gráfico base
    Algunos insisten en querer tener todo resuelto en este punto, pero es crear falsas expectativas y sufrimiento innecesario.
    Es importante que el cliente entienda que el desarrollo es iterativo (hablando de eso, también es importante que el equipo de desarrollo lo entienda ^^).
  2. El diseño gráfico se maqueta con HTML, CSS y Javascript
    Los datos son hardcodeados.
    Algunos insisten en querer maquetar directamente sobre un framework, pero es crear lastre mental innecesario, además de amarrar la maqueta a ese ambiente.
  3. La maqueta es vuelta template, según el framework que se va a usar
    Los datos son mockupeados. Es decir provisto por endpoints que devuelven data hardcodeada.
    Algunos insisten en hacer endpoints reales de una vez, pero también es crear lastre mental innecesario tratar de enfrentar más de un problema a la vez.
  4. La aplicación es provista de datos reales
    Ya que las anteriores etapas han resuelto una cosa a la vez, se reduce bastante el número de posibilidades de error en este punto.
  5. El cliente quiere un cambio
    Procedemos a iterar.
Aquí es donde se presenta el problema. En la atención de los cambios.

Como las revisiones ya se están haciendo con datos reales, las circunstancias presionan para no ir al paso 1, sino iterar sobre el paso 4.

No se actualiza la propuesta gráfica, ni la maqueta en puro HTML. Se percibe como demasiado engorroso. Se hacen los cambios directamente sobre el template con toda la infraestructura corriendo.

Paradójicamente, eso no es más rápido, ni más seguro.

Para hacer cualquier cambio en el template, con la infraestructura corriendo, tienes todo un ecosistema de base de datos, modelos y controladores funcionando... innecesariamente.

Resolver un cambio en un template es un problema más complicado porque tienes que cargarte mentalmente de todas las convenciones y protocolos del framework, y de todas las circunstancias y problemas que otras areas estén atravesando (que la configuración del entorno ha variado, que por ahora no uses este endpoint sino este otro, que hay un servicio que se ha caído y debemos esperar, etc, etc).

En cambio, hacer los cambios sobre la maqueta es un problema aislado, más sencillo y rápido de resolver.

Creo que es mejor resolver los problemas en la maqueta y luego recién llevar esa solución al template.

Si el paso de convertir una maqueta a template no fuera manual sino automático (o si no existiera), creo que sería más sencillo y rápido hacer cambios de UI.

juno-cheeriounophp han sido algunas iniciativas personales para automatizar el paso 3. La idea de unophp se puede adaptar incluso para WordPress.

Pero por ahora, tenemos este problema en Frontend: cómo atender con más facilidad los cambios que se requieren durante las iteraciones del proyecto.

Antipatrón

Yo diría que es un antipatrón que el frontend requiera que todo el motor del proyecto, con su base de datos, endpoints, etc, deba estar corriendo para hacer sus cambios.

Es complejidad innecesaria para esa tarea.

Entiendo que en Integración Contínua se prueban las cosas sobre infraestructuras reales corriendo. Es porque necesitan hacer pruebas en ese nivel. Pero hacer el desarrollo en ese mismo nivel no me parece lo más optimo.

Sería mejor poder aislar esa parte a voluntad, poder crear un entorno donde no exista otra complejidad más allá de lo que quieres resolver, hacer el cambio, y luego, mágicamente, incorporarlo al proyecto completo.

2017/08/09

UX para todo(s)


Nota: Por favor, lee esto con la mente abierta. Si eres frontend, creo lo entenderás. Si eres backend, por favor, no me malinterpretes; también he hecho algo de backend y muchos de mis amigos son backend. No tengo nada en contra de los backend. Excepto quizás la optimización prematura, el overkill (pero eso es algo que se ve en todas partes), y esto.

Encuentro que hay una discusión entre frontend y backend. Entre los chicos que hacen las interfaces para el usuario y los que preparan la data que se mostrará.

Es más o menos así: los backend pretenden que los frontend tienen que usar sus apis cómo a ellos les de la gana de hacerlas.

Por supuesto pueden esgrimir un montón de argumentos; que el mejor modelamiento de las tablas, que la auto documentación, que la optimización, etc.

Lo que yo digo es solamente esto: imagínate que los frontend pretendiéramos que los usuarios tienen que arreglárselas para usar las interfaces que nos diera la gana de hacer.

¿Que así es como haces tus interfaces de usuario? Detente, stop, para un momento.

Por supuesto que durante muchos años se ha hecho así; con la dictadura de los diseñadores sometiendo al usuario y obligándoles a aprender que la opción que buscaban estaba nada más a cuatro clicks de distancia, debajo de un menú desplegable que actuaba cuanto pulsabas la tecla alt después de escape (bueno quizás no tanto, pero seguramente captas la idea).

Pero la abundante oferta de aplicaciones y la despiadada elección de los consumidores ha hecho que recapacitemos y escuchemos al usuario y qué tipo de experiencia realmente le ayuda a conseguir lo que necesita. Porque lo que la UX busca no es que las interfaces sean más bonitas (es un malentendido de marketing); lo que busca es que las interfaces puedan dar lo que se necesita sin obligar a hacer un esfuerzo innecesario.

Además, mira el nombre, "interfaz de usuario", no dice "interfaz del programador frontend". No se supone que debas sentirte cómodo programándola; quizás tengas suerte y sea entretenido, estimulante, o quizás no y sea un dolor de cabeza y un verdadero desafío cómo resolver una interacción; lo importante es que el usuario pueda sentirse cómodo usándola, sin esfuerzos innecesarios.

Pues bien, del mismo modo, la API que se entrega a los frontend es la interfaz con la que nos comunicamos con la fuente de datos. Una buena API no es aquella que sea cómoda o fácil de programar para los backend; puede que lo sea, si se organizan bien, pero es un rollo interno, que no debe atravesar la interfaz. Porque recordemos que se trata de una interfaz: la comodidad y facilidad deben estar del lado de quién la va a usar.

Un backend debería hacer con el frontend el mismo ejercicio que el frontend hace con el usuario. Observarlo, ver cómo va a usar la API, conversar con él acerca de sus necesidades reales, empatizar.

No creo que necesitemos una especie de Frontend eXperience (no más siglas, por favor), sino que comprendamos que los mismos principios que venimos a reconocer como válidos al aplicar UX son aplicables también a la hora de desarrollar interfaces para otros desarrolladores. Puede ser un API REST, o puede ser una librería, o un framework, o cualquier herramienta en general.

En una interfaz, la comodidad y facilidad deben estar del lado de quién la va a usar. Creo que es el principio que guia a la UX y está ayudando a crear más software realmente valioso para los usuarios. Y creo que es hora que apliquemos lo mismo a la relación frontend-backend (y en todas aquellas donde veamos una interfaz), y ayude a crear herramientas realmente valiosas para desarrollar mejor mejores aplicaciones.

2017/06/30

Problemas vs Tareas


Resolvemos problemas cada día. Pero a veces no sabemos qué lo estamos haciendo, ni cómo. Y otras, nadie parece valorarlo.

¿Qué es un problema? Algo cuya solución no es evidente.

Si la solución fuera evidente ya no sería un problema, sino una tarea.

Por ejemplo, si fuera un pintor, tengo los utensilios y la habilidad para pintar tanta area de pared cada hora, ¿cuánto me demoraré en pintar cierta pared?, pues tanto tiempo. El camino es conocido y está libre. Es una tarea.

En cambio, sería un problema si alcanzar alguna parte de la pared no fuera evidente.

O, si en lugar de ser un pintor de brocha gorda tuviera que pintar un retrato. ¿Qué espera mi cliente?, ¿cuál será la pose adecuada para esta persona?, son preguntas cuya respuesta no es evidente. Es un problema.

Lo evidente

¿Qué es evidente? Depende de tus conocimientos y habilidades. Algo evidente para una persona puede no serlo para otra.

Cuando pagas con un billete algo que cuesta menos, es evidente para un adulto que le tienen que dar vuelto. Pero no es tan evidente para un niño que está aprendiendo a comprar en la calle.

Tampoco es evidente que se tenga que distinguir entre problemas y tareas. Pero espero que notes la utilidad de notar la diferencia.

Notando la diferencia

A veces llamamos problemas a tareas que se realizan rutinariamente. O tratamos a quienes resuelven problemas como si estuvieran realizando tareas rutinarias.

Para no formar falsas expectativas, es importante distinguir qué es una tarea y qué es un problema.

Cuando te enfrentas a un problema, sueles encontrar un no dándote el primer encuentro. Este no, muestra que la respuesta no es evidente y aclara que no se trata de una tarea.

Si fallas al realizar una tarea, es que en realidad se trataba de un problema.

Entonces, casi como por instinto, pasas a preguntarte cosas. Si hay algo que se parezca a alguna tarea que conoces. Quizás resolviendo eso primero se aclare cuál es el siguiente paso. O tal vez se trate de dividir el problema en partes conocidas. O, a lo mejor, se pueda expresar alguna parte en términos de algo que ya conozca.

Intentas, fallas, pruebas otra cosa, aciertas, y así vás construyendo un camino hacia la solución.

Cuando realizas una tarea, no aparecen ese tipo de preguntas. Si aparecen, entonces no es una tarea, sino un problema.

Resolviendo

Resolver un problema requiere un trato diferente que realizar una tarea.

Resolver un problema requiere ciertas habilidades adicionales a las que se necesitan para realizar tareas.

Debes ser capaz de aceptar un reto, de imaginar alternativas, de probar un plan y fallar en el intento, de reconocer la información que un intento fallido te puede estar dando, de ubicarte en ese viaje.

Estimando

¿Cuánto tiempo te toma hacer una tarea? Tanto tiempo.

¿Cuánto tiempo te toma resolver un problema? No lo sé, depende del problema.

Pero, un momento, ¿en los exámenes, acaso no hay problemas que hay que resolver en cierto tiempo? Sí, pero en realidad no son problemas para quién propone la prueba, que ya los ha resuelto tantas veces que sabe cuánto es lo que se suele tardar en resolverlo. Sería más correcto llamarlas preguntas.

Un estudiante que no ha estudiado el tema ni practicado preguntas similares, puede tardar mucho más tiempo en resolver una pregunta, porque para él sería realmente un problema. En cambio, otro estudiante, que ha estudiado el tema y practicado ese tipo de preguntas hasta que le resulten tareas, tardará mucho menos.

Puedes ser muy habil realizando tareas y saber cuánto te toma hacerlas. Pero ¿qué pasa cuando te enfrentas a cuestiones cuya respuesta no es evidente?.

Resolver un problema no es un tour al mercado de un pueblo conocido, sino un viaje de exploración. ¿Cuánto tiempo te tomará entrar al bosque desconocido y encontrar allí la fruta que me gusta?

No se puede presupuestar un problema. Sólo se pueden presupuestar tareas.

Si necesitas presupuestar un problema, busca a alguien para quien ese problema sea solo una tarea. O que maneje el proceso para convertir problemas en tareas.

Agile

En el desarrollo agile se trata de tomar un problema y determinar tareas lo más pronto posible para poder presupuestar sobre eso.

Para resolver un problema, se asigna una cantidad pequeña de tiempo y recursos para dar un pequeño paso cada vez. Es como una apuesta. Puede que alcance para resolver algo, puede que no, pero es un riesgo limitado y calculado. Viendo el resultado, podemos decidir si volvemos a apostar por lo mismo o cambiamos de número.

Preparación

Saber cómo manejar un problema es importante, pero hay que reconocer que si no hay alguien capaz de realizar las tareas que surgirán, el problema no se podría resolver.

Familiarizarnos con las tareas nos da más oportunidades de encontrar cosas conocidas al enfrentar un problema.

Nuestro repertorio de tareas conocidas puede ser visto como un vocabulario que nos ayuda a expresar una solución.

Conocer más número de tareas ciertamente puede ayudar. Pero, igual que con las palabras del lenguaje, es importante saber usar eficazmente aquellas que tengamos disponibles.


Herramientas

Es común que se entregue un problema a alguien y se lo deje solo, a ver cómo lo resuelve. Y lo resolvemos, a veces sin saber exactamente cómo. Así aprendimos a interpretar el mundo, a hablar, a tratar con otras personas y situaciones.

Sin embargo, puede ser útil visualizar las cosas que usamos cuando resolvemos problemas. Estas son las que yo suelo distinguir.

Contexto. Es un conjunto de consideraciones que tenemos en cuenta a la hora de tratar con algo. Para abstraer, quitamos consideraciones. Por ejemplo, al tratar con formas geométricas, podemos dejar de lado el peso o el color. Tener claro el contexto y saber aplicar abstracciones ayuda a resolver problemas.

Analogías. Es encontrar un contexto paralelo que ya conozcamos y representar allí nuestro problema, resolverlo, y luego volver al contexto inicial para representar allí la solución.

Semejanza. Así abajo como es arriba. Es encontrar analogías dentro del mismo contexto. (También se podría decir que una analogía es una semejanza entre contextos.)

Patrones. Son como figuras que vemos repetirse en diversos contextos.

Conclusión

Resolver problemas es una actividad que requiere una disposición mental y unas habilidades distintas a hacer algo rutinario.

Pienso que muchas trabas y malentendidos en el desarrollo de proyectos se deben a que no se entiende está diferencia de la actividad creativa.

Creo que hacer la distinción entre problemas, como algo cuya solución no es evidente, y tareas, como una actividad plenamente determinada, es útil para visualizar mejor lo que tenemos frente a nosotros. Para resolver el problema de los problemas.




2017/06/02

Jugando con asteriscos en CSS

Inspirado por el logo de JWT, se me ocurrió jugar a formar asteriscos como una rotación de una barra.

Logo JWT


Para el caso de 6 líneas, probé crear con Sass un mixin que escriba el código repetitivo.

Más artículos