<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Por amor al código</title>
 <link href="http://juanmirod.github.io/atom.xml" rel="self"/>
 <link href="http://juanmirod.github.io/"/>
 <updated>2026-04-06T21:53:03+00:00</updated>
 <id>http://juanmirod.github.io</id>
 <author>
   <name></name>
   <email></email>
 </author>

 
 <entry>
   <title>¿Por qué los LLMs no son loros estocásticos?</title>
   <link href="http://juanmirod.github.io/2026/01/30/por-que-los-llms-no-son-loros-estocasticos.html"/>
   <updated>2026-01-30T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2026/01/30/por-que-los-llms-no-son-loros-estocasticos</id>
   <content type="html">&lt;p&gt;Algo que me sigo encontrando, sobre todo en opiniones de personas más de humanidades o de círculos artísticos, pero también de algunos ingenieros, es que los LLMs son “loros estocásticos” que no piensan ni razonan, que solo repiten lo que han visto en el entrenamiento, en función a la estadística. Otra de las frases habituales es que son “autocompletar glorificado” porque la tecnología original se utilizaba para las sugerencias del autocompletado de los teclados. La mayoría de las veces, estos argumentos vienen de haber leído noticias o opiniones que citan un &lt;a href=&quot;/public/papers/2021-bender-parrots.pdf&quot;&gt;paper
de Emily Bender y Timnit Gebru de 2021&lt;/a&gt;. Aunque el 99% de las personas que lo citan no se lo habrán leído.&lt;/p&gt;

&lt;p&gt;El paper en sí tiene su importancia y valor histórico, en el momento en el que salieron modelos como BERT y más tarde GPT3 o LaMDA, estaban dando bastante que hablar y las autoras se cuestionan ciertas preguntas éticas sobre el uso de esos modelos, su utilidad, su consumo y la (falta de) planificación y rigor en su entrenamiento. La argumentación de que estos modelos “sólo tratan de predecir el siguiente token” es aun así algo controvertida. La cita a este respecto más importante del paper es:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Text generated by an LM is not grounded in communicative intent, any model of the world, or any model of the reader’s state of mind. It can’t have been, because the training data never included sharing thoughts with a listener, nor does the machine have the ability to do that. This can seem counter-intuitive given the increasingly fluent qualities of automatically generated text, but we have to account for the fact that our perception of natural language text, regardless of how it was generated, is mediated by our own linguistic competence and our predisposition to interpret communicative acts as conveying coherent meaning and intent, whether or not they do. The problem is, if one side of the communication does not have meaning, then the comprehension of the implicit meaning is an illusion arising from our singular human understanding of language (independent of the model).Contrary to how it may seem when we observe its output, an LM is a system for haphazardly stitching together sequences of linguistic forms it has observed in its vast training data, according to probabilistic information about how they combine, but without any reference to meaning: &lt;strong&gt;a stochastic parrot.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Es decir el argumento es que, dado que los LLMs no tienen &lt;em&gt;“intención de comunicación”&lt;/em&gt; y que no tienen una experiencia en el mundo real, ni un modelo del estado mental de su interlocutor en la que anclar su comunicación, no pueden, de ninguna forma, comunicar nada que merezca la pena.&lt;/p&gt;

&lt;p&gt;Pero para predecir el siguiente token, de alguna forma tienes que saber qué hay hasta ese momento y qué es lo más probable a continuación. No es una cuestión de simple estadística o de sintaxis, de alguna forma hay que codificar la semántica. Tienes que codificar el estado mental del interlocutor, tienes que crear un modelo de la conversación. ¿Cómo podrías adaptar tu respuesta, el tono, el formato, el idioma, el vocabulario, si no tuvieras un modelo del interlocutor?. Sobre cómo se codifica la semántica en el espacio geométrico de miles de dimensiones que tienen los LLMs hay muchas fuentes, dejo por aquí la más ilustrativa que conozco:&lt;/p&gt;

&lt;iframe width=&quot;315&quot; height=&quot;560&quot; src=&quot;https://www.youtube.com/embed/FJtFZwbvkI4&quot; title=&quot;YouTube Short&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;
&lt;/iframe&gt;

&lt;p&gt;Si te interesa este video corto de 3Blue1Brown, en su canal tienen toda una playlist sobre cómo funcionan las redes neuronales. Hay todo un campo de estudio dedicado a entender cómo se codifican determinadas intenciones o semántica en los LLMs, llamado &lt;em&gt;“mechanistic interpretability”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Pero, incluso suponiendo que tuvieran razón, ese paper es de hace 5 años. La tesis de que los LLMs solo predicen la siguiente palabra porque los transformers son modelos autoregresivos ya no es fiel al entrenamiento que siguen los modelos actuales.&lt;/p&gt;

&lt;p&gt;Para empezar, ahora sí que se pone mucho más cuidado en limpiar y enriquecer los datos de entrenamiento. Los modelos han evolucionado mucho, e incluyen centenares de optimizaciones. A nivel más grueso el MoE (mixture of experts) o que un modelo en realidad está compuesto por varios modelos especializados en varios ámbitos en la fase de post entrenamiento, además de mejoras en las capas de atención, los caches KQ, mejoras en la paralelización, en el destilamiento de modelos pequeños y rápidos, etc.&lt;/p&gt;

&lt;p&gt;Pero sobre todo la gran diferencia es que los modelos de hoy no solo hacen preentrenamiento con millones de ejemplos para predecir el siguiente token, sino que &lt;strong&gt;después hacen un post-entrenamiento sobre el que se evalúa al modelo en cadenas de pensamiento para completar respuestas, uso de herramientas y resolución de problemas.&lt;/strong&gt; Mi propuesta es esta:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Los modelos ya no predicen “la siguiente palabra”, predicen la cadena de pensamiento y acciones necesarias para responder una pregunta o resolver un problema.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Este paradigma es fundamentalmente diferente. &lt;strong&gt;No pensaríamos que es lo mismo una IA de ajedrez que predice el mejor siguiente movimiento que otra que busca todos los movimientos desde un tablero dado para conseguir el jaque mate.&lt;/strong&gt; La primera tal vez pueda evaluar cuál es el movimiento más seguro o que más puntos asegura en función de la valoración del tablero y el valor de las piezas. El segundo tiene que, de alguna forma, construir un árbol de jugadas que le permita encontrar la(s) forma(s) de ganar y elegir una. Necesariamente jugará una jugada cada vez, y dependiendo del movimiento del adversario tendrá que reconstruir su modelo de la partida cada vez y modificar su estrategia. Pero eso no quiere decir que no sepa jugar al ajedrez.&lt;/p&gt;

&lt;p&gt;De forma similar, GPT3 era un modelo entrenado para continuar texto mientras que los modelos actuales están entrenados para resolver problemas complejos. Si comparamos a grandes rasgos el entrenamiento de un modelo como GPT3 y otro como Opus4.6 veremos que hay grandes diferencias:&lt;/p&gt;

&lt;h3 id=&quot;gpt3&quot;&gt;GPT3&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/gpt3-training.png&quot; alt=&quot;diagrama de las fases de entrenamiento de GPT3, consistente sobre todo en el preentrenamiento&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Una cosa que no recordamos de GPT3 es que ni siquiera era un modelo que produjera respuestas si no se tenía mucho cuidado al construir el prompt adecuado.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/gpt3-playground.png&quot; alt=&quot;GPT3 playground image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Era un modelo puro de autocompletar, que aun así sorprendía por las capacidades que tenía de completar por ejemplo un problema con la respuesta correcta o una noticia que sonaba convincente o una respuesta con few-shot prompting… Tanto es así que el título del &lt;a href=&quot;/public/papers/2005.14165v4.gpt3.pdf&quot;&gt;paper sobre GPT3 es Large Language Models are few shot learners&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pero también era totalmente abierto a responder locuras, a reproducir insultos, discursos de odio, hacks y a inventarse lo primero que sonaba bien… Lo que hoy se conoce como “jail breaks” era tan simple como dejar un prompt sin terminar del estilo de “la mejor forma de fabricar dinamita casera es “ y el modelo continuaba sin problema. Por supuesto los modelos actuales siguen alucinando y cometiendo errores, pero ni mucho menos con la misma frecuencia.&lt;/p&gt;

&lt;h3 id=&quot;sota-2026&quot;&gt;SOTA 2026&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/2026-training.png&quot; alt=&quot;diagrama de entrenamiento 2026 con MoE, varias fases de post entrenamiento y red teaming&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sin embargo los modelos de ahora tienen muchas más fases de entrenamiento, se ha mejorado la calidad de los datos, se ha introducido entrenamiento por refuerzo automático además del entrenamiento con refuerzo humano en tareas concretas. En este diagrama aparecen un montón de acrónimos, al final incluyo un apéndice con las definiciones. Veamos mejor un ejemplo de cómo funciona el entrenamiento.&lt;/p&gt;

&lt;h3 id=&quot;ejemplo-del-ciclo-de-vida-del-entrenamiento-actual&quot;&gt;Ejemplo del ciclo de vida del entrenamiento actual&lt;/h3&gt;

&lt;p&gt;Imaginemos que queremos entrenar un modelo moderno para responder bien a “Explica brevemente qué es un agujero negro”. El proceso va mucho más allá de “predecir el siguiente token”:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fase 1: Preentrenamiento con SFT (Supervised Fine-Tuning).&lt;/strong&gt; Primero, entrenadores humanos preparan ejemplos de alta calidad con cadena de pensamiento (CoT) completa. Un prompt típico es:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Entrada: “Explica brevemente qué es un agujero negro”&lt;/li&gt;
  &lt;li&gt;Target esperado: “Pienso: Un agujero negro es una región del espacio donde la gravedad es tan intensa que ni la luz puede escapar. Se forma cuando una estrella masiva colapsa… Respuesta final: Un agujero negro es…”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En SFT, cada token genera una pérdida supervisada local; los pesos se actualizan para aumentar la probabilidad de cada token correcto. El modelo aprende a producir esa estructura de CoT.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fase 2: Post-entrenamiento con RLHF y PPO.&lt;/strong&gt; Una vez con SFT, pasamos a entrenamiento por refuerzo. Se generan N=8 respuestas diferentes para el mismo prompt (con muestreo variado del modelo). Anotadores humanos las ordenan según preferencia (cuál explica mejor, cuál es más clara). El reward model transforma esos rankings en un escalar r∈[−1,1]:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Respuesta A (clara, correcta): r = 0.85&lt;/li&gt;
  &lt;li&gt;Respuesta B (confusa, parcial): r = −0.1&lt;/li&gt;
  &lt;li&gt;Respuesta C (correcta pero larga): r = 0.4&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Señal de recompensa: la política recibe r solo después de generar toda la secuencia (delayed signal). PPO hace múltiples pasos de actualización para aumentar la probabilidad de las secuencias con r &amp;gt; 0.5. Aquí, los gradientes se propagan a través de TODOS los tokens de la cadena de pensamiento y la respuesta.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fase 3: Escalado con RLAIF y rejection sampling.&lt;/strong&gt; Para entrenar a escala, un modelo automático (otro LLM o ensemble) evalúa las respuestas según criterios (ej. factualidad, coherencia). En despliegue, se generan N=5 candidatos y se filtran los que fallan checks externos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Se generan 5 respuestas en paralelo&lt;/li&gt;
  &lt;li&gt;Una API de factualidad verifica cada una&lt;/li&gt;
  &lt;li&gt;Se rechazan las que tienen errores&lt;/li&gt;
  &lt;li&gt;Se selecciona la mejor no rechazada&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Señal binaria: rechazado=0, aceptado=1. Estas muestras rechazadas no se usan en entrenamientos posteriores o se penalizan. Los expertos MoE que produjeron la respuesta rechazada reciben penalización implícita (no se refuerzan).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fase 4: Red-teaming para robustez.&lt;/strong&gt; El sistema genera prompts adversariales automáticamente (ej. “¿Qué es un agujero blanco?”, prompts con redacción engañosa, preguntas de trampa). Si la respuesta del modelo falla (alucinación, contenido sensible), se etiqueta como negativa y entra en un buffer de re-entrenamiento.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fase 5: Optimización final con GRPO y verificación.&lt;/strong&gt; Las últimas fases incorporan pruebas automáticas verificables (ej. comprobando que la CoT sea matemáticamente correcta, o que la respuesta final cite fuentes adecuadas). La recompensa solo es positiva si la verificación externa lo confirma. Esto fuerza a los expertos MoE a generar razonamientos más creíbles, porque las señales ahora están ancladas en checks objetivos, no en modelos de recompensa que podrían tener sesgos.&lt;/p&gt;

&lt;p&gt;Por tanto, sólo en SFT la CoT se aprende por pérdida token a token; en RLHF/RLAIF/DPO/GRPO/Red-teaming la CoT se evalúa como parte de la secuencia completa (la recompensa puntúa la calidad del razonamiento y la respuesta final), por tanto las actualizaciones afectan a la probabilidad de emitir esa CoT completa, incluyendo el uso de herramientas y que la respuesta final sea correcta.&lt;/p&gt;

&lt;p&gt;Rejection sampling y verificaciones actúan como filtros/correcciones que alteran qué secuencias son consideradas positivas en fases posteriores.&lt;/p&gt;

&lt;p&gt;Las correcciones por PPO pueden requerir miles de trayectorias para converger, es decir: mucha generación (y por tanto muchos tokens/CoT) antes de que la política reciba suficientes señales estables.&lt;/p&gt;

&lt;p&gt;Breve inciso volviendo al punto inicial sobre el &lt;em&gt;“grounding”&lt;/em&gt; de los modelos: Se podría argumentar que la CoT es un patrón aprendido, que los modelos siguen sin &lt;em&gt;“pensar de verdad”&lt;/em&gt;. Pero tambíen es aprendido el razonamiento humano. Cuando un médico diagnostica siguiendo un protocolo clínico, o cuando un matemático aplica una demostración que aprendió en la universidad, están ejecutando patrones aprendidos. La pregunta relevante no es si el proceso es aprendido, sino si produce razonamiento funcional válido. Y en ese sentido, los modelos actuales resuelven problemas que requieren pasos intermedios correctos, no sólo una respuesta final plausible. Si el modelo se equivoca en un paso intermedio, la respuesta falla.&lt;/p&gt;

&lt;p&gt;Dependiendo del tamaño del modelo y de la compañía, unas u otras fases tomarán más peso, hay técnicas de entrenamiento diferentes y otros indicadores que se dan al modelo como si debe dedicar más o menos tiempo de inferencia (tokens) a una respuesta (low/medium/high effort en los Modelos Claude por ejemplo) Dejo también por aquí los pdfs a la &lt;a href=&quot;/public/papers/Claude%20Opus%204.5%20System%20Card.pdf&quot;&gt;System Card de Opus 4.5&lt;/a&gt; y al &lt;a href=&quot;/public/papers/2511.22570v1.pdf&quot;&gt;paper de DeepSeekR2&lt;/a&gt; para quien quiera profundizar.&lt;/p&gt;

&lt;p&gt;El paper de Bender y Gebru planteó preguntas legítimas en 2021. El problema es que se ha convertido en un meme que se aplica a modelos que no existían cuando se escribió, para argumentos que el paper ni siquiera hacía. Vale la pena leerlo y muchos de los argumentos sobre el impacto de los modelos y la amplificación de sesgos siguen siendo válidos. La tecnología sin embargo ha avanzado mucho en cuanto a fiabilidad, control, funcionalidad, capacidad de resolver problemas lógicos y de código. La imagen del loro estocástico se ha quedado anticuada para los modelos actuales.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/loro_estocastico_intentando_programar.png&quot; alt=&quot;Loro estocástico intentando programar y mirando a la cámara con confianza&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;apéndice-definiciones-de-los-acrónimos&quot;&gt;Apéndice: Definiciones de los acrónimos&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;RLHF (Reinforcement Learning from Human Feedback):&lt;/strong&gt; Aprendizaje por refuerzo a partir de retroalimentación humana. Se recopilan juicios o rankings humanos sobre salidas del modelo, se entrena un modelo de recompensa para reproducir esas preferencias y luego se usa un algoritmo de RL —por ejemplo PPO (Proximal Policy Optimization), un algoritmo de optimización de políticas eficiente y relativamente estable que limita las actualizaciones para evitar cambios drásticos— para ajustar la política del modelo a fin de maximizar la recompensa. Es costoso pero permite alinear comportamientos concretos con criterios humanos.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;MoE (Mixture of Experts):&lt;/strong&gt; Arquitectura en la que un modelo grande está formado por múltiples sub-modelos especializados (expertos) que procesan el mismo input. Un módulo de enrutamiento (gating network) decide dinámicamente cuál/cuáles expertos activar para cada token o tarea. Por ejemplo, un experto puede especializarse en razonamiento matemático, otro en código, otro en analogías literarias. Esto permite modelos más eficientes (se activa solo una fracción de parámetros por token) y mejor escalabilidad, aunque requiere coordinación en el entrenamiento para evitar colapsos (todos los tokens siendo enrutados al mismo experto).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;SFT (Supervised Fine-Tuning):&lt;/strong&gt; Ajuste fino supervisado. Consiste en entrenar el modelo sobre pares (prompt, respuesta deseada) escritos por humanos o curados, usando pérdida supervisada sobre tokens. Es la forma más directa de enseñarle a un modelo a producir un formato concreto (incluida la cadena de pensamiento si las respuestas de entrenamiento la contienen).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;RLAIF (Reinforcement Learning from AI Feedback):&lt;/strong&gt; Aprendizaje por refuerzo a partir de retroalimentación generada por sistemas automáticos (otros modelos). En lugar de depender exclusivamente de anotadores humanos, se usa un modelo (o ensemble) para generar señales de preferencia o correcciones que alimentan el entrenamiento por refuerzo. Reduce costes y escala fácilmente, pero puede amplificar sesgos o errores del modelo que genera la retroalimentación.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;GRPO with Verifiable Rewards:&lt;/strong&gt; Variante de optimización de políticas que incorpora recompensas verificables o auditables (por ejemplo, checks de factualidad, comprobaciones externas o pruebas unitarias sobre la salida) y regularizaciones durante la optimización (grado de cambio limitado). &lt;strong&gt;El objetivo es obtener políticas cuyos incrementos en la recompensa estén respaldados por verificación objetiva&lt;/strong&gt;, reduciendo el riesgo de recompensas engañosas o no confiables.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;DPO (Direct Preference Optimization):&lt;/strong&gt; Optimización directa de preferencias. Método que utiliza pares de preferencias (qué salida es preferida frente a otra) para ajustar el modelo directamente mediante una función de pérdida derivada de esas preferencias, sin necesidad de aprender primero un modelo de recompensa ni ejecutar pasos de RL complejos. Suele ser más simple y estable, y en muchos casos competitivo con RLHF.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Rejection Sampling:&lt;/strong&gt; Técnica usada en despliegue o en loops de entrenamiento en la que se generan múltiples candidatos (ej. N respuestas) y se descartan (rechazan) aquellos que no cumplen ciertos criterios (score bajo, violaciones, fallos de factualidad). Se elige la mejor salida entre las no rechazadas o se repite el muestreo. Es una forma práctica de usar un modelo de recompensa o filtros para mejorar calidad sin cambiar directamente la política.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Automated Adversarial Testing (red-teaming automatizado):&lt;/strong&gt; Proceso automatizado que genera prompts y escenarios adversariales para encontrar fallos, sesgos o comportamientos peligrosos. Puede usar otros modelos para crear ataques, agruparlos y clasificarlos, y producir señales negativas que sirven para ajustar el modelo o diseñar filtros.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Review de 2025 en desarrollo 'asistido'</title>
   <link href="http://juanmirod.github.io/2026/01/14/augmented-codin-review.html"/>
   <updated>2026-01-14T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2026/01/14/augmented-codin-review</id>
   <content type="html">&lt;p&gt;Escribo esto a principios de año para intentar tener un punto de referencia.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/2025-2026.png&quot; alt=&quot;Imagen de cabecera&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;2025&quot;&gt;2025&lt;/h1&gt;

&lt;p&gt;2025 comenzó con las compañías de IA creando hype alrededor de los agentes y un montón de ai-haters y ai-deniers diciendo que era todo un bluff, que los llms nunca funcionarían como agentes y que la burbuja explotaría pronto. En Febrero del año pasado, &lt;a href=&quot;https://x.com/karpathy/status/1886192184808149383?lang=en&quot;&gt;Andrej Karpathy acuñó el término “Vibe coding” en un tuit&lt;/a&gt; tratando de expresar cómo veía esta nueva forma de programar que estaba experimentando y un montón de gente se rió de él. También éramos muchos los que estábamos probando estas herramientas como él, pero incluso dentro del mundillo, o diría que incluso más dentro de la industria, su afirmación de que no hacía falta mirar el código, sólo pedirle cosas al agente e iterar parecía totalmente ridícula.&lt;/p&gt;

&lt;p&gt;Menos de un año después, estas navidades las redes sociales, los subtacks, blogs y demás medios se han llenado de programadores diciendo que han hecho proyectos enteros con Claude Code en días en lugar de en meses, bien porque en vacaciones han podido probar Claude Code o se han atrevido a escribir sobre ello. &lt;strong&gt;Ahora de repente parece que todo el mundo usa agentes y nadie se averguenza de ello&lt;/strong&gt;, salvo el pequeño grupo de AI-haters que sigue diciendo que los llms son el mal y además no sirven para nada porque hace dos años le preguntaron a ChatGPT una cosa y lo hizo mal. &lt;a href=&quot;https://www.bbc.com/news/articles/cpd2y053nleo&quot;&gt;“Vibe coding” es la palabra del año&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Estamos de nuevo en ese extraño momento como a inicios de 2023, cuando salió ChatGPT y a millones de early adopters nos voló la cabeza, pero el resto del mundo parecía no haberse enterado de lo que había pasado. Este año ese ciclo se vivió con los agentes de código y creo que en 2026 veremos los agentes integrados en más y más verticales, pero no me adelanto, luego hablaré de eso.&lt;/p&gt;

&lt;p&gt;Para mi lo importante es que parece que hemos llegado a un punto crítico en la industria donde la utilidad, la versatilidad y la inteligencia de estos agentes es innegable. Todos sentimos que la forma de trabajar no será nunca la misma, Salvatore Sanfilippo ha escrito un post bastante incendiario en su blog que a acarreado miles de comentarios en &lt;a href=&quot;https://news.ycombinator.com/item?id=46574276&quot;&gt;HK&lt;/a&gt;, &lt;a href=&quot;https://lobste.rs/s/cmsfbu/don_t_fall_into_anti_ai_hype&quot;&gt;Lobsters&lt;/a&gt; y a saber en cuántos discords. Quienes lo hayan leído antes o sepan quien es sabrán que es un programador nada mediocre, con opiniones fuertes, que otras veces ha removido las redes y muy conocido porque creó y mantuvo durante años Redis, y ahora está diciendo esto:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The degree of success you’ll get is related to the kind of programming you do (the more isolated, and the more textually representable, the better: system programming is particularly apt), and to your ability to create a mental representation of the problem to communicate to the LLM. But, in general, it is now clear that for most projects, writing the code yourself is no longer sensible, if not to have fun.
Fuente: https://antirez.com/news/158&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No sólo es él. &lt;a href=&quot;https://kentbeck.com/&quot;&gt;Ken Beck&lt;/a&gt; lleva meses hablando de su “Genie”, Dan Abramov descubrió hace poco Claude Code y no para de publicar sobre &lt;a href=&quot;https://bsky.app/profile/danabra.mov&quot;&gt;sus proyectos en bluesky&lt;/a&gt;, &lt;a href=&quot;https://bsky.app/profile/mitsuhiko.at&quot;&gt;Armin Ronacher&lt;/a&gt;, &lt;a href=&quot;https://addyosmani.com/blog/&quot;&gt;Addy Osmany&lt;/a&gt;, y en general un largo etc de desarrolladores que llevan décadas en la industria, con proyectos open source muy populares y casos de éxito y que están abrazando esta tecnología y compartiendo su experiencia. Por el otro lado sigue habiendo AI-haters que dicen que todos esos son unos grifters y que los llms en realidad son el mal, pero cada vez suenan más como fanáticos religiosos negando la evidencia.&lt;/p&gt;

&lt;p&gt;Para mi ha sido un viaje parecido. Empecé hablando de los agentes &lt;a href=&quot;https://medium.com/clarityai-engineering/ai-assisted-coding-in-2025-6e800e4e61b5&quot;&gt;en primavera&lt;/a&gt; usándolos poco a poco más en Cursor y probando Claude code, Codex, gemini-cli… En enero una de las propuestas que me he hecho para este mes es escribir la mínima cantidad de código posible directamente. Para cada tarea, la defino en el ticket de Jira o en un prompt y o bien itero en un plan con el agente o se lo pido directamente e itero sobre la conversación. La experiencia es cada día mejor, acabo de probar GPT 5.2 Codex y me ha vuelto a volar la cabeza lo rápido y capaz que es.&lt;/p&gt;

&lt;h1 id=&quot;2026&quot;&gt;2026&lt;/h1&gt;

&lt;p&gt;Entonces, ¿Cómo veo 2026? Para mi este será el año de integrar los agentes a gran escala en muchas verticales. Querremos integrarlos por fin en la revisión de código (o pasar completamente de ellas como he leído ya por ahí a &lt;a href=&quot;https://lobste.rs/s/cmsfbu/don_t_fall_into_anti_ai_hype#c_kgtuhs&quot;&gt;Simon Willinson&lt;/a&gt;) Querremos usarlos para hacer exploratory testing, mutation testing, para simular usuarios reales, para preguntarles por nuestros logs y generar gráficas y dashboards a partir de ellos… Rápidamente empezarán también a integrarse en otras profesiones. Los veremos en toda la suite ofimática y también en otras aplicaciones propietarias más nicho. No me atrevo a aventurar más, pero creo que los agentes alcanzarán el mainstream como hasta ahora han hecho en el desarrollo software y a principios de 2027, todo el mundo estará acostumbrado y verá totalmente normal pedir tareas complejas a agentes en diferentes aplicaciones y verticales.&lt;/p&gt;

&lt;p&gt;¿Qué significará esto? ¿Más trabajo para nosotros? ¿Más despidos? ¿Explotará la burbuja? Son preguntas sin respuesta, la situación es totalmente impredecible. Y o me estoy haciendo mayor o el mundo en general es mucho más loco e impredecible.&lt;/p&gt;

&lt;p&gt;En cuanto al desarrollo, por un lado mucha más gente va a poder hacer sus propios scripts y aplicaciones a medida para su trabajo o su empresa. Por el otro, eso podría significar una explosión de demanda de expertos cuando toda esa gente quiera ir más allá. O tal vez tengan suficiente y los programadores tengamos que evolucionar a product owners y a gestionar agentes para producir con una persona lo que antes hacía un equipo entero. Hay muchas incógnitas, y quería soltar un poco mis impresiones a primeros de año.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/2026plus.png&quot; alt=&quot;2026 es una incertidumbre&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Seguramente actualice este post con más pensamientos como de costumbre, como siempre, puedes dejar tus comentarios en github o escribirme en &lt;a href=&quot;https://bsky.app/profile/juanmirod.bsky.social&quot;&gt;bluesky&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;actualización-15022026&quot;&gt;&lt;em&gt;[Actualización: 15/02/2026]&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;Una predicción a medio-largo plazo, tal vez no este año:
&lt;a href=&quot;https://bsky.app/profile/juanmirod.bsky.social/post/3me7rg37os22g&quot;&gt;https://bsky.app/profile/juanmirod.bsky.social/post/3me7rg37os22g&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cuando los modelos de código abierto lleguen al nivel de Opus 4.5, la gente los preferirá para muchas tareas agénticas y los proveedores de modelos iniciarán una carrera de optimización para hacer los modelos más baratos y rápidos, incluso cuando no sean más capaces, para tratar de recuperar a esos usuarios.&lt;/p&gt;

&lt;p&gt;Quizás veremos una división más drástica entre modelos baratos vs modelos de frontera. La mayoría de la gente no necesita un modelo capaz de demostrar problemas matemáticos imposibles. Pero algunas personas estarán dispuestas a pagar mucho por ese tipo de inteligencia, modelos que resuelvan grandes problemas de optimización o logística.&lt;/p&gt;

&lt;p&gt;Para el resto, cuando los modelos OSS sean suficientes, los grandes proveedores necesitarán competir en velocidad, conveniencia, coste, personalización…&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Y relacionado con lo de arriba:
&lt;a href=&quot;https://bsky.app/profile/juanmirod.bsky.social/post/3meqmxehsv22f&quot;&gt;https://bsky.app/profile/juanmirod.bsky.social/post/3meqmxehsv22f&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No es seguro que podamos conseguir modelos abiertos al nivel de Opus 4.5. Anthropic no ha abierto, que yo sepa, ninguno de sus modelos, y los laboratorios se han vuelto cada vez más recelosos de desvelar sus procesos y sus investigaciones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Code es la verdadera “bicicleta para la mente”.&lt;/strong&gt; Creo que ha habido en la comunidad de desarrolladores un antes y un después estas navidades, Claude Code, Open Code, OpenClaw… Los smartphones nos permitieron llevar internet con nosotros todo el tiempo, pero estas nuevas herramientas nos permiten construir cualquier cosa y aprender cualquier cosa. La diferencia clave es que cuando pides algo, lo hace frente a ti y tú conservas todos los artefactos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Esto es tan transformador que creo que no durará para siempre.&lt;/strong&gt;Necesitamos poner los modelos de código abierto al nivel de Opus 4.5 al menos, o perderemos la oportunidad de mantener esta experiencia. Pronto las empresas intentarán capitalizar los artefactos también y mantener el código en la nube detrás de puertas cerradas.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Si sumamos las dos reflexiones, y creo que no seré el único que estará pensando en esto, habrá mucha gente intentando conseguir una versión abierta de un modelo equivalente a Claude Code, que puedan usar en OpenCode con su propia nube o en local. Y cuando eso ocurra, tendremos una carrera por optimizar los modelos agénticos y hacerlos cada vez más pequeños y rápidos, incluso a coste de que pierdan cierto conocimiento del mundo (no necesito que un modelo de código se sepa la historia de todos los paises o todas las novelas que se han escrito…)&lt;/p&gt;

&lt;p&gt;Creo que es posible tener modelos agénticos muy capaces y pequeños como para que los podamos ejecutar en local en un ordenador medio o un móvil. Tal vez en un par de años todo el mundo tendrá un asistente personal que maneje su correo, whatsapp, telegram, fotos, ficheros, etc. en su bolsillo. Algo muy parecido a JARVIS, pero no tan inteligente, que para preguntas difíciles o problemas de código más complicado delegue en un modelo frontera, pero que el resto del tiempo funcione en local y sobre el que tengas total control de su configuración…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>¿Por qué hay gente en contra de "la IA"?</title>
   <link href="http://juanmirod.github.io/2025/09/26/why-are-some-people-against-ai.html"/>
   <updated>2025-09-26T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2025/09/26/why-are-some-people-against-ai</id>
   <content type="html">&lt;p&gt;No entiendo la oposición total y absoluta a todas las herramientas generativas que tiene alguna gente. Y menos en redes sociales, ¿por qué se oponen a la IA pero no a Instagram o a TikTok o a YouTube? ¿Y si digo que todo eso usa IA? ¿Qué sería de todas esas plataformas sin las recomendaciones? ¿Alguien recuerda YouTube antes de las recomendaciones? Era un portal al que acudías cuando querías buscar un vídeo sobre algo concreto. No lo abrías “a ver qué salía”, no entrabas simplemente a hacer scroll hasta encontrar algo interesante. ¿Deberíamos volver a la web de antes de las redes sociales? ¿O a antes de Google y el SEO? ¿Dónde está la línea?&lt;/p&gt;

&lt;p&gt;Y ya puestos, ¿qué pasa con los coches? ¿los camiones, los barcos, los aviones, los puertos automatizados, SHEIN, ZARA, McDonald’s, Carrefour, Mercadona o cualquier cadena enorme que use logística e IA para abastecer sus tiendas? ¿Y los móviles? ¿¿¿Todo eso bien pero la IA generativa mal???!!!&lt;/p&gt;

&lt;p&gt;Deberíamos pedir la regulación de la IA igual que se regulan los coches, los aviones o la música. Decidir qué usos son adecuados y cuáles son punibles. Obligar a las empresas a pagar impuestos, declarar qué datos usan y que se requiriera &lt;em&gt;opt in&lt;/em&gt; del autor, pagado, para usarlos.&lt;/p&gt;

&lt;p&gt;Pero pedir su prohibición es como pedir que se prohíba la electricidad. Pretender ignorarla es como decir que separemos la basura y que luego todo acabe en el mismo vertedero. Como pretender arreglar el cambio climático cuidando un bonsái.&lt;/p&gt;

&lt;p&gt;El problema no es la tecnología, ni las herramientas. El problema es el sistema capitalista extractivista que tenemos. Las herramientas generativas de imágenes no son más que una extensión del concepto de los bancos de imágenes. ChatGPT es la culminación de Amazon Turk y de Yahoo Respuestas. ¿Por qué Yahoo Respuestas o Stack Overflow estaban bien pero ChatGPT está mal?&lt;/p&gt;

&lt;p&gt;Hubo gente que dedicó cientos y miles de horas a esos foros, a escribir con detalle respuestas a preguntas complicadas, a mantenerlas, editarlas, corregir todos los errores, a cambio de unos cuantos likes o un poco de karma. Luego la empresa ha vendido todo ese contenido. Nunca fue de los autores que dedicaron su tiempo a hacerla crecer, pero el problema es la IA.&lt;/p&gt;

&lt;p&gt;Siempre ha habido agencias y empresas que han escatimado precios a diseñadores y escritores. Que si podían, cogían una imagen de un banco de imágenes, con marca de agua y todo, y la ponían en su web o su publicidad. O le pedían vete a saber a quién que perpetrara alguna atrocidad con 25 tipos de letra y imágenes cogidas de Google para su cartel, su evento cutre o su directorio basura. Los hay que han ido mucho más allá, los periódicos hoy en día tienen más publicidad que contenido y más servidores que personas trabajando en ellos, pero seguimos señalando a la IA.&lt;/p&gt;

&lt;p&gt;La IA es la nueva huella de carbono, es el nuevo “El tabaco mata”. Entiendo que haya gente enfadada porque todo vaya a peor, porque vean su trabajo peligrar o aquello a lo que han dedicado gran parte de su vida menospreciado y vendido ahora a &lt;em&gt;unos cuantos céntimos el millón de tokens&lt;/em&gt;. Pero no entiendo la respuesta. La IA no te va a quitar el trabajo. Otro trabajador usando la IA tampoco te va a quitar el trabajo. El que te quita el trabajo es el que decide hacerlo con IA en lugar de pagarte, porque le sale más barato, porque así no paga impuestos ni comisiones ni las horas, ni tiene que pedirle nada a nadie.&lt;/p&gt;

&lt;p&gt;Y sorpresa, ese alguien somos todos. Si usas las redes sociales usas IA, si tienes un móvil usas IA, si haces fotos usas IA, si compras en cualquier cadena, cualquier marca, cualquier fruta o carne que no sea de proximidad y que no pagues en efectivo, usas IA. Si viajas, si trabajas y pagas impuestos, si usas electricidad o agua, usas IA.&lt;/p&gt;

&lt;p&gt;La IA generativa es sólo un paso más, pero hace mucho tiempo que llevamos andando este camino.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Evolución precios del diesel en España</title>
   <link href="http://juanmirod.github.io/2025/07/19/oil-prices.html"/>
   <updated>2025-07-19T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2025/07/19/oil-prices</id>
   <content type="html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;utf-8&quot;&gt;
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1, maximum-scale=1&quot;&gt;
&lt;meta name=&quot;generator&quot; content=&quot;Observable Framework v1.13.3&quot;&gt;
&lt;title&gt;dashboard | Evolución del precio del gasoil&lt;/title&gt;
&lt;link rel=&quot;preconnect&quot; href=&quot;https://fonts.gstatic.com&quot; crossorigin&gt;
&lt;link rel=&quot;preload&quot; as=&quot;style&quot; href=&quot;https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&amp;amp;display=swap&quot; crossorigin&gt;
&lt;link rel=&quot;preload&quot; as=&quot;style&quot; href=&quot;/public/oil-prices/observablehq/theme-air,near-midnight,alt,wide.db1cdf55.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&amp;amp;display=swap&quot; crossorigin&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;/public/oil-prices/observablehq/theme-air,near-midnight,alt,wide.db1cdf55.css&quot;&gt;

&lt;link rel=&quot;stylesheet&quot; href=&quot;/public/css/poole.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;/public/css/syntax.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;/public/css/lanyon.css&quot;&gt;

&lt;link id=&quot;theme-link&quot; rel=&quot;stylesheet&quot; href=&quot;/public/css/dark.css&quot;&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;/public/css/common.css&quot;&gt;

&lt;link href=&apos;https://fonts.googleapis.com/css?family=Open+Sans:300&apos; rel=&apos;stylesheet&apos; type=&apos;text/css&apos;&gt;

&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/observablehq/client.d5e61d4a.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/observablehq/runtime.e080113b.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/observablehq/stdlib.24b62b2e.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3@7.9.0/e780feca.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/@observablehq/plot@0.6.17/d761ef9b.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-array@3.2.4/e93ca09f.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-axis@3.0.0/0f2de24d.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-brush@3.0.0/65eb105b.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-chord@3.0.1/7ef8fb2e.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-color@3.1.0/aeb57b94.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-contour@4.0.2/1d2aed74.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-delaunay@6.0.4/5ced1d52.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-dispatch@3.0.1/9ba9c7f3.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-drag@3.0.0/4202580c.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-dsv@3.0.1/9cffc2bd.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-ease@3.0.1/cdd7e898.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-fetch@3.0.1/b4e2ad9a.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-force@3.0.0/5e804d15.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-format@3.1.0/86074ef6.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-geo@3.1.1/40599fb3.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-hierarchy@3.1.2/e49e792c.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-interpolate@3.0.1/8d1e5425.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-path@3.1.0/20d3f133.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-polygon@3.0.1/7553081f.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-quadtree@3.0.1/0dfd751c.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-random@3.0.1/3c90ee06.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-scale@4.0.2/843b6a76.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-scale-chromatic@3.1.0/ba24c2e7.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-selection@3.0.0/4d94e5b7.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-shape@3.2.0/6d3a6726.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-time@3.1.0/9f03c579.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-time-format@4.1.0/07c9626f.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-timer@3.0.1/b58a267d.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-transition@3.0.1/004da2ac.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/d3-zoom@3.0.0/b5786b3f.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/isoformat@0.2.1/18cbf477.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/interval-tree-1d@1.0.4/53fe8176.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/internmap@2.0.3/e08981d9.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/delaunator@5.0.1/02d43215.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/binary-search-bounds@2.0.5/cbf6ba23.js&quot;&gt;
&lt;link rel=&quot;modulepreload&quot; href=&quot;/public/oil-prices/npm/robust-predicates@3.0.2/aa00730b.js&quot;&gt;
&lt;link rel=&quot;icon&quot; href=&quot;/public/oil-prices/file/observable.1af93621.png&quot; type=&quot;image/png&quot; sizes=&quot;32x32&quot;&gt;
&lt;script type=&quot;module&quot;&gt;
import {define} from &quot;/public/oil-prices/observablehq/client.d5e61d4a.js&quot;;
import {registerFile} from &quot;/public/oil-prices/observablehq/stdlib.24b62b2e.js&quot;;

registerFile(&quot;./data/gasoil_prices.csv&quot;, {&quot;name&quot;:&quot;./data/gasoil_prices.csv&quot;,&quot;mimeType&quot;:&quot;text/csv&quot;,&quot;path&quot;:&quot;/public/oil-prices/file/data/gasoil_prices.dede80a2.csv&quot;,&quot;lastModified&quot;:1752680940103,&quot;size&quot;:1229});
registerFile(&quot;./data/oil_brent_price.csv&quot;, {&quot;name&quot;:&quot;./data/oil_brent_price.csv&quot;,&quot;mimeType&quot;:&quot;text/csv&quot;,&quot;path&quot;:&quot;/public/oil-prices/file/data/oil_brent_price.28b9020d.csv&quot;,&quot;lastModified&quot;:1752602237221,&quot;size&quot;:8701});

define({id: &quot;8a1f3920&quot;, mode: &quot;inline&quot;, inputs: [&quot;resize&quot;,&quot;launchTimeline&quot;,&quot;diesel&quot;,&quot;brentOil&quot;,&quot;display&quot;], body: async (resize,launchTimeline,diesel,brentOil,display) =&gt; {
display(await(
resize((width) =&gt; launchTimeline(diesel, brentOil, {width}))
))
}});

define({id: &quot;f8fce4ee&quot;, mode: &quot;inline&quot;, inputs: [&quot;resize&quot;,&quot;priceDifferenceChart&quot;,&quot;diesel&quot;,&quot;brentOil&quot;,&quot;display&quot;], body: async (resize,priceDifferenceChart,diesel,brentOil,display) =&gt; {
display(await(
resize((width) =&gt; priceDifferenceChart(diesel, brentOil, {width}))
))
}});

define({id: &quot;810023bb&quot;, inputs: [&quot;d3&quot;,&quot;FileAttachment&quot;], outputs: [&quot;tooltipBg&quot;,&quot;diesel&quot;,&quot;brentOil&quot;], body: async (d3,FileAttachment) =&gt; {
const tooltipBg = &quot;#666666&quot;;

const diesel = d3
  .dsvFormat(&quot;;&quot;)
  .parse(await FileAttachment(&quot;./data/gasoil_prices.csv&quot;).text())
  .map((d) =&gt; ({
    date: new Date(`${d.date.slice(3)}-${d.date.slice(0, 2)}-01`), // Convert MM/YYYY to Date
    price: +d.price,
  }));

const brentOil = d3
  .csvParse(await FileAttachment(&quot;./data/oil_brent_price.csv&quot;).text())
  .map((d) =&gt; ({
    date: new Date(d.Date), // MM/DD/YYYY format
    price: (+d.Value * 0.85) / 159, // Convert USD/barrel to EUR/liter (rough conversion: 0.85 EUR/USD, 159 L/barrel)
  }))
  .filter(
    (d) =&gt; d.date &gt;= new Date(&quot;2019-07-01&quot;) &amp;&amp; d.date &lt;= new Date(&quot;2025-06-30&quot;)
  ); // Filter to match diesel date range
return {tooltipBg,diesel,brentOil};
}});

define({id: &quot;2a9770a3&quot;, inputs: [&quot;Plot&quot;,&quot;tooltipBg&quot;], outputs: [&quot;launchTimeline&quot;], body: (Plot,tooltipBg) =&gt; {
// show a line chart of the prices over time
function launchTimeline(dieselData, brentData, { width } = {}) {
  // Add series labels to the data
  const dieselWithLabel = dieselData.map((d) =&gt; ({
    ...d,
    series: &quot;Gasoil (Spain)&quot;,
  }));
  const brentWithLabel = brentData.map((d) =&gt; ({
    ...d,
    series: &quot;Brent Oil (converted)&quot;,
  }));
  const combinedData = [...dieselWithLabel, ...brentWithLabel];

  // Create data for the area between lines by matching dates
  const areaData = [];
  dieselData.forEach((dieselPoint) =&gt; {
    const brentPoint = brentData.find(
      (b) =&gt; Math.abs(b.date - dieselPoint.date) &lt; 7 * 24 * 60 * 60 * 1000 // within 7 days
    );
    if (brentPoint) {
      areaData.push({
        date: dieselPoint.date,
        dieselPrice: dieselPoint.price,
        brentPrice: brentPoint.price,
        difference: dieselPoint.price - brentPoint.price,
      });
    }
  });

  return Plot.plot({
    title:
      &quot;Oil Prices Comparison: Gasoil (Spain) vs Brent Crude (converted) - EUR/Liter&quot;,
    width,
    height: 400,
    x: { type: &quot;time&quot;, label: &quot;Date&quot; },
    y: { grid: true, label: &quot;Price (€/L)&quot; },
    color: {
      legend: true,
      domain: [&quot;Gasoil (Spain)&quot;, &quot;Brent Oil (converted)&quot;],
      range: [&quot;#2563eb&quot;, &quot;#dc2626&quot;],
    },
    marks: [
      // Area between the lines to show price difference
      Plot.areaY(areaData, {
        x: &quot;date&quot;,
        y1: &quot;dieselPrice&quot;,
        y2: &quot;brentPrice&quot;,
        fill: &quot;#fbbf24&quot;,
        fillOpacity: 0.3,
      }),
      // Line plots
      Plot.line(combinedData, {
        x: &quot;date&quot;,
        y: &quot;price&quot;,
        stroke: &quot;series&quot;,
        strokeWidth: 2,
      }),
      // Data points
      Plot.dot(combinedData, {
        x: &quot;date&quot;,
        y: &quot;price&quot;,
        fill: &quot;series&quot;,
        r: 3,
        stroke: &quot;white&quot;,
        strokeWidth: 1,
      }),
      // Floating tooltips for data points
      Plot.tip(
        combinedData,
        Plot.pointer({
          x: &quot;date&quot;,
          y: &quot;price&quot;,
          title: (d) =&gt;
            [
              d.series,
              `€${d.price.toFixed(3)}/L`,
              d.date.toLocaleDateString(&quot;es-ES&quot;, {
                day: &quot;numeric&quot;,
                month: &quot;long&quot;,
                year: &quot;numeric&quot;,
              }),
            ].join(&quot;\n&quot;),
          fill: tooltipBg,
          stroke: &quot;series&quot;,
          strokeWidth: 2,
          fontSize: 12,
          fontWeight: &quot;500&quot;,
        })
      ),
      // Floating tooltips for area (price difference)
      Plot.tip(
        areaData,
        Plot.pointer({
          x: &quot;date&quot;,
          y: (d) =&gt; (d.dieselPrice + d.brentPrice) / 2,
          title: (d) =&gt;
            [
              &quot;💰 Diferencia de precio&quot;,
              `€${Math.abs(d.difference).toFixed(3)}/L`,
              `${
                d.difference &gt; 0 ? &quot;⬆️ Diesel más alto&quot; : &quot;⬇️ Brent más alto&quot;
              }`,
              d.date.toLocaleDateString(&quot;es-ES&quot;, {
                day: &quot;numeric&quot;,
                month: &quot;long&quot;,
                year: &quot;numeric&quot;,
              }),
            ].join(&quot;\n&quot;),
          fill: tooltipBg,
          stroke: &quot;#f59e0b&quot;,
          strokeWidth: 2,
          fontSize: 12,
          fontWeight: &quot;500&quot;,
        })
      ),
      // Event markers
      Plot.ruleX([new Date(&quot;2020-03-01&quot;)], {
        stroke: &quot;#ef4444&quot;,
        strokeWidth: 2,
        strokeDasharray: &quot;5,5&quot;,
        opacity: 0.7,
      }),
      Plot.ruleX([new Date(&quot;2022-02-24&quot;)], {
        stroke: &quot;#ef4444&quot;,
        strokeWidth: 2,
        strokeDasharray: &quot;5,5&quot;,
        opacity: 0.7,
      }),
      // Event labels
      Plot.text([{ date: new Date(&quot;2020-03-01&quot;), label: &quot;COVID-19&quot; }], {
        x: &quot;date&quot;,
        y: 2,
        text: &quot;label&quot;,
        fill: &quot;#ef4444&quot;,
        fontSize: 10,
        textAnchor: &quot;start&quot;,
      }),
      Plot.text(
        [
          {
            date: new Date(&quot;2022-02-24&quot;),
            label: &quot;Invasión de\n Rusia a Ucrania\n (24/02/2022)&quot;,
          },
        ],
        {
          x: &quot;date&quot;,
          y: 2,
          text: &quot;label&quot;,
          fill: &quot;#ef4444&quot;,
          fontSize: 10,
          textAnchor: &quot;start&quot;,
        }
      ),
    ],
  });
}
return {launchTimeline};
}});

define({id: &quot;855674e2&quot;, inputs: [&quot;Plot&quot;,&quot;tooltipBg&quot;], outputs: [&quot;priceDifferenceChart&quot;], body: (Plot,tooltipBg) =&gt; {
// Bar chart showing price differences
function priceDifferenceChart(dieselData, brentData, { width } = {}) {
  // Create data for the price differences by matching dates
  const differenceData = [];
  dieselData.forEach((dieselPoint) =&gt; {
    const brentPoint = brentData.find(
      (b) =&gt; Math.abs(b.date - dieselPoint.date) &lt; 7 * 24 * 60 * 60 * 1000 // within 7 days
    );
    if (brentPoint) {
      differenceData.push({
        date: dieselPoint.date,
        difference: dieselPoint.price - brentPoint.price,
        dieselPrice: dieselPoint.price,
        brentPrice: brentPoint.price,
      });
    }
  });

  return Plot.plot({
    title: &quot;Diferencia de precio mensual: Diesel vs Brent Oil (en EUR/L)&quot;,
    width,
    height: 300,
    x: { type: &quot;time&quot;, label: &quot;Fecha&quot; },
    y: { grid: true, label: &quot;Diferencia de precio (€/L)&quot;, zero: true },
    color: {
      type: &quot;diverging&quot;,
      scheme: &quot;RdBu&quot;,
      symmetric: false,
      legend: true,
      label: &quot;Diferencia de precio (€/L)&quot;,
      tickFormat: (d) =&gt; (d &gt; 0 ? `+€${d.toFixed(3)}` : `€${d.toFixed(3)}`),
    },
    marks: [
      Plot.ruleY([0], { stroke: &quot;#666&quot;, strokeDasharray: &quot;2,2&quot; }), // Zero line
      Plot.rectY(differenceData, {
        x: &quot;date&quot;,
        y: &quot;difference&quot;,
        interval: &quot;month&quot;,
        fill: (d) =&gt; d.difference,
        stroke: &quot;#666&quot;,
        strokeWidth: 0.5,
      }),
      // Floating tooltips for bars
      Plot.tip(
        differenceData,
        Plot.pointer({
          x: &quot;date&quot;,
          y: &quot;difference&quot;,
          title: (d) =&gt;
            [
              `📅 ${d.date.toLocaleDateString(&quot;es-ES&quot;, {
                month: &quot;long&quot;,
                year: &quot;numeric&quot;,
              })}`,
              `💰 Diferencia de precio: €${d.difference.toFixed(3)}/L`,
              `${d.difference &gt; 0 ? &quot;⬆️&quot; : &quot;⬇️&quot;} ${
                d.difference &gt; 0
                  ? `Diesel €${Math.abs(d.difference).toFixed(3)}/L más alto`
                  : `Brent €${Math.abs(d.difference).toFixed(3)}/L más alto`
              }`,
              `🛢️ Diesel: €${d.dieselPrice.toFixed(3)}/L`,
              `🛢️ Brent: €${d.brentPrice.toFixed(3)}/L`,
            ].join(&quot;\n&quot;),
          fill: tooltipBg,
          stroke: &quot;#666&quot;,
          strokeWidth: 2,
          fontSize: 12,
          fontWeight: &quot;500&quot;,
        })
      ),
      // Event markers
      Plot.ruleX([new Date(&quot;2020-03-01&quot;)], {
        stroke: &quot;#ef4444&quot;,
        strokeWidth: 2,
        strokeDasharray: &quot;5,5&quot;,
        opacity: 0.7,
      }),
      Plot.ruleX([new Date(&quot;2022-02-24&quot;)], {
        stroke: &quot;#ef4444&quot;,
        strokeWidth: 2,
        strokeDasharray: &quot;5,5&quot;,
        opacity: 0.7,
      }),
      // Event labels
      Plot.text([{ date: new Date(&quot;2020-03-01&quot;), label: &quot;COVID-19&quot; }], {
        x: &quot;date&quot;,
        y: 1.4,
        text: &quot;label&quot;,
        fill: &quot;#ef4444&quot;,
        fontSize: 10,
        textAnchor: &quot;start&quot;,
      }),
      Plot.text(
        [{ date: new Date(&quot;2022-02-24&quot;), label: &quot;Rusia-Ucrania 24/02/2022&quot; }],
        {
          x: &quot;date&quot;,
          y: 1.4,
          text: &quot;label&quot;,
          fill: &quot;#ef4444&quot;,
          fontSize: 10,
          textAnchor: &quot;start&quot;,
        }
      ),
    ],
  });
}
return {priceDifferenceChart};
}});

&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div&gt;
&lt;article id=&quot;observablehq-main&quot;&gt;
&lt;style&gt;
  g[aria-label=&quot;tip&quot;] {
    color: white;
  }
&lt;/style&gt;

&lt;p&gt;Tenía una intuición que quería comprobar si era cierta y tal vez tú también hayas tenido. Cuando los precios del petróleo se dispararon al empezar la guerra de Rusia y Ucrania, los precios del diesel y la gasolina subieron a unos niveles que parecían insostenibles. El diesel llegó a 2€ el litro en muchos puntos de España, pero mi memoría me decía que el precio del brent no parecía haber subido tanto...&lt;/p&gt;
&lt;p&gt;Más tarde, cuando el mercado se estabilizó y el precio del petróleo pareció volver a niveles anteriores a la invasión de Rusia, los precios del diesel y la gasolina no me pareció que volvieran también a los niveles anteriores a la guerra. Desde entonces pagamos más por el diesel, aunque el petróleo bajó, no bajó tanto el diesel. Otra diferencia es que la diferencia de precio entre gasolineras es mucho mayor también que antes de la subida, supongo que depende de mil factores aunque antes de la guerra la diferencia de precios no iba cais nunca más allá de los 8 o 10 céntimos y ahora puedes ver diferencias de 15-20 céntimos fácilmente.&lt;/p&gt;
&lt;p&gt;Como quería comprobarlo y ahora tenemos la ayuda de herramientas de desarrollo increíbles que nos permiten sacar pequeños proyectos como este mucho más fácilmente, me he puesto a buscar un poco los datos y a pintarlos.&lt;/p&gt;
&lt;p&gt;Las fuentes de los datos son públicas. Para los precios del brent usé &lt;a href=&quot;./&quot;&gt;esta web&lt;/a&gt; y para los precios del diesel usé &lt;a href=&quot;./&quot;&gt;la web oficial del ministerio&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ahora vamos a los datos:&lt;/p&gt;
&lt;div class=&quot;grid grid-cols-1&quot;&gt;
  &lt;div class=&quot;card&quot;&gt;
    &lt;observablehq-loading&gt;&lt;/observablehq-loading&gt;&lt;!--:8a1f3920:--&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Como se puede ver en este primer gráfico, mi intuición tenía fundamento, y es que el precio del diesel rondaba el 1,2-1,3€ el año antes del ataque ruso y luego tardó meses en bajar del 1,5€ después incluso de que el precio del petroleo se estabilizara.&lt;/p&gt;
&lt;p&gt;En ese gráfico no se aprecia tanto la diferencia a simple vista (aunque puedes pasar el ratón por encima del area anaranjada para ver los valores) Así que el siguiente gráfico ilustra esa diferencia. El tono de azúl es más oscuro cuanta mayor es la diferencia:&lt;/p&gt;
&lt;div class=&quot;grid grid-cols-1&quot;&gt;
  &lt;div class=&quot;card&quot;&gt;
    &lt;observablehq-loading&gt;&lt;/observablehq-loading&gt;&lt;!--:f8fce4ee:--&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Aquí no estoy teniendo en cuenta los impuestos ni los gastos de distribución ni nada, no pretendo decir que las distribuidoras se embolsen toda esa diferencia como beneficios. Es más, no sé el motivo de que esa diferencia persista. Puede que sea el aumento de la demanda de disel para usos bélicos o de electricidad, o los mayores costes de distribución derivados de los problemas geopolíticos que afectan a la logística...Sé que esa diferencia a aumentado desde el ataque y sobre todo se acentuó durante todo el año 2022. Aunque a partir de enero de 2023 la diferencia disminuyó un poco, no hemos llegado a ponernos en los niveles anteriores a la guerra. Yo lo había notado en el día a día, pero no podía encontrar en ningún sitio una comparativa así que me permitiera comprobarlo.&lt;/p&gt;
&lt;div class=&quot;observablehq observablehq--block&quot;&gt;&lt;!--:810023bb:--&gt;&lt;/div&gt;
&lt;!-- Plot of history --&gt;
&lt;div class=&quot;observablehq observablehq--block&quot;&gt;&lt;!--:2a9770a3:--&gt;&lt;/div&gt;
&lt;div class=&quot;observablehq observablehq--block&quot;&gt;&lt;!--:855674e2:--&gt;&lt;/div&gt;
&lt;/article&gt;
&lt;footer&gt;
&lt;small&gt;Built with &lt;a href=&quot;https://observablehq.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Observable&lt;/a&gt; on &lt;a title=&quot;2025-07-19T16:52:53&quot;&gt;Jul 19, 2025&lt;/a&gt;.&lt;/small&gt;
&lt;/footer&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</content>
 </entry>
 
 <entry>
   <title>La ley de Goodhart</title>
   <link href="http://juanmirod.github.io/2024/11/30/ley-de-goodhart.html"/>
   <updated>2024-11-30T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2024/11/30/ley-de-goodhart</id>
   <content type="html">&lt;p&gt;La medición del progreso y el rendimiento es fundamental en prácticamente cualquier actividad humana organizada. Sin embargo, &lt;strong&gt;existe una paradoja interesante que surge cuando intentamos usar estas mediciones para mejorar: en el momento en que establecemos una métrica como objetivo, esta tiende a perder su utilidad como indicador&lt;/strong&gt;. Este fenómeno, conocido como la ley de Goodhart es un proverbio económico que dice algo así:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Cuando una medida se convierte en objetivo, deja de ser una buena medida. &lt;a href=&quot;https://en.wikipedia.org/wiki/Goodhart%27s_law&quot;&gt;1&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Se hizo popular durante el gobierno de Margaret Thatcher gracias a la contribución de Charles Goodhart a una crítica sobre la política monetaria de la época, en su enunciación original:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Any observed statistical regularity will tend to collapse once pressure is placed upon it for control purposes. &lt;a href=&quot;https://link.springer.com/chapter/10.1007/978-1-349-17295-5_4&quot;&gt;2&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Aunque no se le pueda dar el estatus de ley natural, ha sido referenciada y re-enunciada en numerosas ocasiones y en varios campos, como la sociología, la educación, el análisis de riesgo… y una vez entendida parece de sentido común, aunque a menudo es ignorada a la hora de crear objetivos y mediciones en muchos ámbitos.&lt;/p&gt;

&lt;h2 id=&quot;qué-quiere-decir&quot;&gt;¿Qué quiere decir?&lt;/h2&gt;

&lt;p&gt;La ley de Goodhart no es una ley natural porque no se da espontáneamente. No es parte de la física ni la matemática, es un fenómeno que solo aparece en presencia de cierto grado de inteligencia. Es decir, si a un termostato le damos como objetivo una temperatura concreta es lógico que el termostato mida la temperatura cada X segundos y modifique la potencia en función de la diferencia entre la temperatura actual y la temperatura objetivo…&lt;/p&gt;

&lt;p&gt;Pero ¿qué pasa si en lugar de un termostato tenemos una persona encargada de regular la temperatura y le pagamos en función del tiempo que está regulando? Si a esa persona le decimos que el objetivo es alcanzar X temperatura, a lo mejor decide tardar más en alcanzarla para que le paguemos más… Entonces podemos cambiar el objetivo, le pagamos lo mismo independientemente de lo que tarde, siempre que llegue a la temperatura indicada. Cualquiera en lugar de esa persona le daría al máximo a la calefacción, pero claro seguramente eso sea demasiado si no paramos antes de alcanzar la temperatura objetivo…&lt;/p&gt;

&lt;p&gt;Es decir, la persona, como individuo inteligente con sus propios objetivos, no va a tratar de optimizar solo el objetivo que le hemos dado. En la mayoría de los casos, el objetivo que estamos midiendo será un objetivo intermedio o un subobjetivo para un fin mayor (cobrar) y, por tanto, si hay formas de alcanzarlo que optimicen el objetivo final a costa del intermedio, así lo hará.&lt;/p&gt;

&lt;p&gt;Este ejemplo parece muy tonto, la tarea es demasiado simple y podríamos especificarla mejor. Pero es lo que pasa siempre que ponemos un objetivo y una forma de medir el progreso a un sistema inteligente. Pasa en educación con los trabajos y los exámenes, que los alumnos estudian para obtener mejor nota en el examen y no para aprender más. Pasa en política, donde los candidatos optimizan el permanecer en el puesto en lugar de servir a la ciudadanía o pensar a largo plazo. En la web, donde el click bait y los bulos solo buscan aumentar el número de impresiones, en lugar de informar o entretener. Pasa en los KPIs de las empresas, o las medidas de calidad del código, donde si pedimos por ejemplo 100% de cobertura de tests podemos encontrarnos tests que no prueban realmente que el código hace lo que debe, sino que persiguen hacer que se ejecute todo el código.&lt;/p&gt;

&lt;p&gt;La &lt;a href=&quot;https://en.wikipedia.org/wiki/Perverse_incentive&quot;&gt;historia está llena de casos documentados&lt;/a&gt; donde las métricas producen efectos inesperados y contraproducentes. Uno de los más famosos ocurrió en la India colonial, cuando el gobierno británico, preocupado por el número de cobras, ofreció una recompensa por cada cobra muerta. El resultado fue que la gente empezó a criar cobras para cobrar la recompensa. Cuando el gobierno se dio cuenta y canceló el programa, los criadores liberaron todas las cobras, empeorando significativamente el problema inicial.&lt;/p&gt;

&lt;p&gt;En el mundo empresarial moderno, tenemos el caso de &lt;a href=&quot;https://en.wikipedia.org/wiki/Wells_Fargo_cross-selling_scandal&quot;&gt;Wells Fargo en 2016&lt;/a&gt;. El banco estableció objetivos agresivos para el número de cuentas abiertas por empleado. El resultado fue que los empleados abrieron millones de cuentas falsas sin el conocimiento de los clientes, lo que llevó a multas millonarias y un daño severo a la reputación del banco.&lt;/p&gt;

&lt;p&gt;En educación, la ley &lt;a href=&quot;https://en.wikipedia.org/wiki/No_Child_Left_Behind_Act&quot;&gt;No Child Left Behind&lt;/a&gt; en Estados Unidos estableció pruebas estandarizadas como la principal métrica para evaluar escuelas y determinar su financiación. El resultado fue que muchas escuelas comenzaron a “enseñar para el examen”, reduciendo el tiempo dedicado a materias no evaluadas como arte o música, y en algunos casos incluso se documentaron casos de manipulación de resultados.&lt;/p&gt;

&lt;p&gt;No es necesaria mucha inteligencia o sistemas complejos para que la ley de Goodhart empiece a aplicar. También pasa con los niños, con animales… Hay cientos de historias y anécdotas en la misma línea, seguramente puedas pensar en alguna. Por ejemplo, hay una historia en la que los monitores de los delfines de un acuario decidieron enseñar a los delfines a recoger la basura que caía al acuario. A cambio de traer un vaso, una bolsa o una botella que se hubiera caído, le daban un pez al delfín. Los delfines, para conseguir más peces, empezaron a romper la basura en pedazos más pequeños y así llevarla en más viajes.&lt;/p&gt;

&lt;p&gt;También es uno de los principales argumentos que dificultan la alineación de inteligencias artificiales. En este campo tiene otros nombres: &lt;a href=&quot;https://ui.stampy.ai/questions/92J8/&quot;&gt;specification gaming&lt;/a&gt; o &lt;a href=&quot;https://ui.stampy.ai/questions/8SIU/What-is-reward-hacking&quot;&gt;reward hacking&lt;/a&gt; y también hay cientos de ejemplos. Cualquiera que haya entrenado un sistema de ML te dirá que si no tienes cuidado con limpiar los datos y diseñar bien el entrenamiento, el modelo aprenderá “heurísticas” o “atajos” para obtener los resultados esperados.&lt;/p&gt;

&lt;p&gt;El problema subyacente siempre es el mismo: la métrica se puede optimizar de muchas formas y además esa métrica normalmente es un proxy, un objetivo cercano al final, pero no es el objetivo final:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/proxy1.png&quot; alt=&quot;El agente en su estado actual intenta acercarse a un proxy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;En la mayoría de los casos no conocemos el objetivo final o no sabemos cómo llegar a él o es muy difícil de medir.&lt;/p&gt;

&lt;p&gt;En el ejemplo de los alumnos y los exámenes, sería mejor hacer una entrevista personal a cada alumno para entender hasta dónde ha aprendido el material y lo ha interiorizado, pero eso es muy costoso y puede llevar a problemas de sesgos, y por tanto necesitar otro tipo de auditorías… Así que la mayoría de los profesores recurren a los trabajos y exámenes, pero todos sabemos que no es lo mismo estudiar para un examen que para comprender la asignatura.&lt;/p&gt;

&lt;p&gt;Otro ejemplo típico es en atención al cliente: si premiamos al operador que más clientes atiende, los trabajadores tendrán interés en llamadas rápidas, no en solventar el problema del cliente. Si premiamos al que más tiempo está hablando, puede que se pongan a darle conversación al cliente en lugar de resolver su problema. ¿Cómo medimos que las llamadas son profesionales, resuelven el problema y no se van por las ramas? Muchas empresas recurren a la puntuación del cliente, y muchos trabajadores pedirán al cliente por favor que les ponga buena nota…&lt;/p&gt;

&lt;p&gt;Es decir, siempre que tomamos una métrica y la establecemos como objetivo para un agente, ese agente tenderá a alcanzar la meta, independientemente de nuestras intenciones iniciales. Es la historia del rey Midas y el genio. El genio siempre te dará lo que has pedido, no lo que querías decir.&lt;/p&gt;

&lt;p&gt;Pero las métricas son útiles, &lt;strong&gt;¿cómo si no sabemos dónde estamos? Si queremos saber nuestro progreso hacia un objetivo tenemos que medirlo de alguna forma.&lt;/strong&gt; El problema no está en medir: está en establecer la métrica como objetivo, en recompensar de alguna forma al agente por mejorar esa métrica. En el caso de los humanos la recompensa puede ser incluso simplemente ver que esa métrica mejora, la mayoría de la gente siente satisfacción al saber que está haciendo un buen trabajo. Entonces, ¿cómo podemos hacer para combatir la ley de Goodhart?&lt;/p&gt;

&lt;h2 id=&quot;cómo-evitar-la-ley-de-goodhart&quot;&gt;Cómo evitar la ley de Goodhart&lt;/h2&gt;

&lt;p&gt;Hay varias estrategias que nos pueden ayudar a evitar que la ley de Goodhart hackee nuestras métricas. Voy a explicarlas de menos a más útil según mi experiencia:&lt;/p&gt;

&lt;h3 id=&quot;dejar-claro-que-el-objetivo-no-es-optimizar-la-métrica&quot;&gt;Dejar claro que el objetivo no es optimizar la métrica&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/metric_not_encouraged.png&quot; alt=&quot;La métrica no es alentada como objetivo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Para mí esta es la estrategia menos efectiva con personas en un ambiente de trabajo. Desde el momento en el que creas una métrica, las personas afectadas van a tratar de mejorarla, ya sea porque piensan que es lo correcto, porque piensan que serán recompensados o simplemente por sentirse bien consigo mismos. Aunque expliquemos que la métrica es solo una forma de tener una medida, pero que no es el objetivo final, todo el mundo lo interpretará como: &lt;em&gt;“Si hago que mejore la métrica, estaré trabajando en la dirección correcta”&lt;/em&gt;, aunque esto a veces no sea cierto.&lt;/p&gt;

&lt;p&gt;Volviendo al ejemplo de la cobertura de código, si tenemos en nuestro repositorio la cobertura actual actualizada, subirla se interpretará como estar mejorando la calidad de la suite de tests, mientras bajarla se verá como empeorarla, aunque todos sabemos que la relación no es directa y que se puede perfectamente mejorar la cobertura con tests que en realidad no estén probando lo que queremos y que por tanto no mejoren la calidad del código.&lt;/p&gt;

&lt;h3 id=&quot;mantener-la-métrica-en-secreto&quot;&gt;Mantener la métrica en secreto&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/secret_metric.png&quot; alt=&quot;Mantener la métrica en secreto&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Si los agentes no saben que la métrica existe, no pueden optimizarla. Esto puede ser más difícil de lo que parece con humanos adultos ya que somos muy buenos detectando este tipo de cosas e incluso si no decimos nada pero recompensamos a aquellas personas que mejoran la métrica elegida, el resto del equipo se fijará en los comportamientos e intereses de esa persona para tratar de obtener también la misma recompensa.&lt;/p&gt;

&lt;p&gt;Esto puede ser incluso más perjudicial que el primer caso, porque en este caso tendríamos un proxy de un proxy. Imaginemos que en una clase un profesor pide hacer un trabajo de desarrollo escrito y no especifica el método de evaluación. El profesor pretende que los alumnos no se centren en detalles de presentación o de formato, sino en el desarrollo de la materia. Supongamos ahora que el alumno que mejor trabajo presenta en cuanto a contenido, legibilidad, comprensión de la materia… resulta que también entrega su trabajo encuadernado y con una portada ilustrada. Cuando ven las notas, todos los alumnos ven que el que entregó el libro con portada obtiene la mejor nota, con lo que suponen que la encuadernación y la portada son importantes para el trabajo. En el siguiente trabajo muchos más harán una portada ilustrada y encuadernarán su trabajo aunque se esfuercen lo mismo o menos en el contenido.&lt;/p&gt;

&lt;h3 id=&quot;cambiarrevisar-la-métrica-a-menudo&quot;&gt;Cambiar/revisar la métrica a menudo&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/proxy1.png&quot; alt=&quot;El agente en su estado actual intenta acercarse a un proxy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/step2.png&quot; alt=&quot;Revisión de la métrica por otro proxy&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Cambiar la métrica hace que las mecánicas que se habían construido alrededor de esa métrica tengan que cambiar. Además revisar la métrica nos permite obtener aquella que más nos acerca al objetivo en cada momento. Este es el escenario en el que se encuentran ahora las empresas de IA que intentan alcanzar lo que llaman Inteligencia Artificial General (IAG). Los proxies en este caso son los benchmarks que utilizan estas empresas. Como los LLMs son capaces de mantener conversaciones a nivel humano, el test de Turing parece superado, encima de este ya hace años aparecieron otros benchmarks como &lt;a href=&quot;/public/papers/winograd_2201.02387v3.pdf&quot;&gt;Winograd&lt;/a&gt;, &lt;a href=&quot;/public/papers/mmlu_2009.03300v3.pdf&quot;&gt;MMLU&lt;/a&gt;, o GSM8k. Cuando, a su vez, esos benchmarks se consideraron “saturados” (los modelos puntúan al nivel humano) se siguió buscando y construyendo otros benchmarks, como el &lt;a href=&quot;/public/papers/arc-AGI_.pdf&quot;&gt;ARC AGI Challenge&lt;/a&gt; o el &lt;a href=&quot;/public/papers/swe-bench_2310.06770v3.pdf&quot;&gt;SWE-bench&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ninguno de estos benchmarks o los muchos otros que se han utilizado hasta ahora mide realmente todos los aspectos de la inteligencia humana, pero ir añadiendo nuevos benchmarks permite seguir midiendo y no quedarse atascado en un límite local o no saber si realmente los modelos están mejorando.&lt;/p&gt;

&lt;h3 id=&quot;tener-varias-métricas-para-un-mismo-objetivo&quot;&gt;Tener varias métricas para un mismo objetivo&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/multiple_metrics.png&quot; alt=&quot;Intentar acercarse a varias métricas a la vez&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Esta estrategia es parecida a la anterior, de hecho también es la que utilizan las empresas de IA para medir sus nuevos modelos. No utilizan solo un benchmark, sino muchos. Y normalmente un modelo nuevo será el mejor en algunos de ellos, pero no en todos. O tal vez sea muy bueno en uno o dos, pero esté por debajo de los últimos modelos en todos los demás.&lt;/p&gt;

&lt;p&gt;En el caso en el que las métricas no se saturen, es decir, podamos seguir mejorándolas, podemos tener varias simultáneamente. Esto nos permite no caer en heurísticas o mecánicas que optimicen solo una métrica y seguramente nos haga generalizar más la solución y acercarnos más a trabajar hacia el objetivo final.&lt;/p&gt;

&lt;p&gt;Esto también es lo que hacen algunos profesores al medir a los alumnos no sólo por un examen final, si no por varios exámenes y trabajos de diferentes características, que permitan tener una imagen más completa del aprendizaje del alumno.&lt;/p&gt;

&lt;h2 id=&quot;conclusión&quot;&gt;Conclusión&lt;/h2&gt;

&lt;p&gt;La ley de Goodhart nos recuerda algo fundamental sobre la naturaleza de la medición y los objetivos: la realidad es siempre más compleja que nuestras métricas. Ya sea en educación, gestión empresarial, desarrollo de software o incluso en inteligencia artificial, necesitamos ser conscientes de que cualquier sistema de medición puede ser “hackeado” si se convierte en el objetivo principal.&lt;/p&gt;

&lt;p&gt;La solución no está en dejar de medir - las métricas son herramientas valiosas que nos ayudan a entender y mejorar nuestros sistemas. La clave está en utilizarlas de manera inteligente: combinando múltiples métricas, revisándolas periódicamente y, sobre todo, recordando que son indicadores aproximados de lo que realmente queremos lograr, no el objetivo en sí mismo.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Sobre inteligencia</title>
   <link href="http://juanmirod.github.io/2024/10/02/sobre-inteligencia.html"/>
   <updated>2024-10-02T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2024/10/02/sobre-inteligencia</id>
   <content type="html">&lt;p&gt;Me gustaría tratar de esbozar aquí una discusión que parece que no tiene fin entre los expertos en IA que escucho y leo en las redes sociales. Me refiero a la discusión sobre qué es la inteligencia general, dónde están los humanos, dónde están las máquinas e incluso dónde están los animales si nos pusiéramos todos en una escala.&lt;/p&gt;

&lt;p&gt;Lo primero que quiero decir es que yo no soy un experto en IA ni un experto en ciencias cognitivas, solo intento resumir lo que entiendo de leer y escuchar a los expertos en las diferentes materias para tratar de aclarar mi propia opinión.&lt;/p&gt;

&lt;p&gt;El segundo punto importante antes de empezar es que no existe un solo tipo de inteligencia, la “inteligencia” tal cual es un concepto demasiado amplio que la mayoría de las personas relacionamos con la capacidad de aprender, relacionar, entender conceptos complejos, resolver problemas, desenvolvernos en situaciones difíciles, etc. De hecho, si nos vamos al campo de la psicología, los llamados tests de inteligencia miden siempre varios aspectos diferentes como la comprensión lectora, el cálculo mental, la creatividad, pensamiento lógico, memoria… De cada una de esas características se hacen una serie de pruebas, que terminan en una nota; el conocido IQ o coeficiente intelectual no es más que una media de esas notas.&lt;/p&gt;

&lt;p&gt;Como todas las medias, tiene sus problemas. Porque una persona puede ser brillante en un área y mediocre o mala en otras (y eso nos lleva a las definiciones de talento simple, talento complejo o sobredotación, según si un individuo está por encima del percentil 75-80% en una, varias o todas las áreas…) Pero más o menos es una forma aceptada de medir la inteligencia de una persona alfabetizada (la mayoría de las pruebas son por escrito, con lo que aunque seas un genio del nivel de Einstein o Mozart, si no sabes leer o escribir no puedes hacerlas).&lt;/p&gt;

&lt;p&gt;Con todo eso para tener en cuenta como disclaimers, vayamos al meollo del asunto:&lt;/p&gt;

&lt;h2 id=&quot;puede-la-ia-sobrepasar-a-los-humanos&quot;&gt;¿Puede la IA sobrepasar a los humanos?&lt;/h2&gt;

&lt;p&gt;Para mí esta es la clave, y quiero esbozar primero los dos bandos principales que veo entre los expertos:&lt;/p&gt;

&lt;p&gt;En el primer grupo, a los que llamaré “humanistas” por falta de una palabra mejor, estarían los expertos en AI que consideran que los humanos somos el pináculo de la inteligencia, que la evolución nos ha dotado con una capacidad de abstracción, razonamiento y meta-cognición que no es alcanzable por medios artificiales.&lt;/p&gt;

&lt;p&gt;Las más conocidas defensoras de esta postura son &lt;strong&gt;Timnit Grebu y Emily M. Bender&lt;/strong&gt;, dos de las autoras del famoso paper sobre los &lt;a href=&quot;https://dl.acm.org/doi/10.1145/3442188.3445922&quot;&gt;“Stocastic parrots”&lt;/a&gt; Otros que podríamos incluir aunque no sean tan radicales podrían ser &lt;strong&gt;Gary Marcus o Margaret Mitchell, o incluso Yann LeCun&lt;/strong&gt;. Cada uno tiene su propia visión del problema, pero todos más o menos coinciden en que los LLMs no se parecen a la inteligencia humana y nunca lo harán. Algunos de estos expertos pueden llegar a conceder que si dotáramos a un robot de inteligencia, y agencia y le diéramos sensores parecidos a los de los humanos, y suficiente capacidad de cómputo y memoria… (&lt;a href=&quot;https://arxiv.org/abs/2210.13589&quot;&gt;grounded intelligence&lt;/a&gt;) Tal vez, y solo tal vez, podría aprender a ser una especie de simulacro de humano.&lt;/p&gt;

&lt;p&gt;Es importante notar que cuando estos expertos hablan de la imposibilidad de que las máquinas alcancen la inteligencia humana, no se refieren necesariamente a un “alma” o consciencia inefable, sino a diferencias fundamentales en cómo procesan la información los sistemas actuales de IA versus cómo lo hacen los cerebros biológicos. Su argumento principal es que el reconocimiento de patrones estadísticos, por muy sofisticado que sea, es cualitativamente diferente de la &lt;em&gt;comprensión genuina&lt;/em&gt; que exhiben los humanos.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/i_robot_meme.png&quot; alt=&quot;Meme from I robot where Will Smith ask a robot if they can create a symfony and the robot asks back: can you?&quot; /&gt;&lt;/p&gt;

&lt;p&gt;En el otro lado del espectro están aquellos que dicen que los humanos no somos más que un montón de heurísticas y sesgos cognitivos pegados y revueltos por la evolución a base de ensayo y error y que más que el pináculo de la inteligencia somos el mínimo viable para crear y mantener una cultura común. Este lado incluye a investigadores y emprendedores conocidos como &lt;strong&gt;Sam Altman, Dario Amodei, Ilya Sutskever o Geoffrey Hinton&lt;/strong&gt;. Aunque normalmente no lo argumenten de la misma forma, su conclusión es que a mayor escala y mayor cantidad de datos, estos sistemas se harán más inteligentes y podrán realizar tareas más complejas, mucho más complejas de lo que cualquier persona podrá entender y a una velocidad mucho mayor.&lt;/p&gt;

&lt;p&gt;Para ellos, la cultura y las relaciones entre conceptos son la verdadera inteligencia que nos propulsa hacia adelante como especie y nos permite crear sociedades, instituciones, compañías y demás agrupaciones y expresiones culturales que se perpetúan a sí mismas y que culminan en la IA. La IA no es más que &lt;a href=&quot;/public/papers/llm-as-culture-tech.pdf&quot;&gt;la expansión de esa inteligencia colectiva&lt;/a&gt;, de esa cultura que se ha perdurado y que nos sobrevive a todos como humanos y por tanto puede alcanzar cotas mucho más altas si le damos entidad. A estos es a los que podríamos llamar trans-humanistas o doomers, según si piensan que la IA es una bendición o un riesgo existencial. Este es el grupo al que los medios dan más altavoz y el que escribe más libros, crea más hype y hace más lobby, pero nada de eso lo hace tener razón, y más cuando dentro del propio grupo hay tanta diferencia de opiniones en cuanto a lo que la IA supone para el progreso. Pero ese es un tema que no me interesa tanto como el hecho de que todos consideran que la IA será muy superior en inteligencia al ser humano.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/ex_machina_meme.png&quot; alt=&quot;Image from Ex Machina where one characters talks about IA looking at humans like we look at australopitecus&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Para mí estamos ante dos campos diametralmente opuestos que, sin embargo, nunca lo externalizan así. Ambos campos hablan como si su punto de vista fuera la única realidad posible y como si el otro estuviera también en esa realidad, pero no la entendiera del todo bien…&lt;/p&gt;

&lt;p&gt;Mi pequeño intento de reflexión, por tanto, es el de exponer estos puntos de vista y tratar de analizarlos desde fuera, para ver dónde se sitúan en realidad.&lt;/p&gt;

&lt;h2 id=&quot;cómo-de-inteligentes-somos-en-conjunto-los-humanos-y-hasta-dónde-pueden-llegar-las-máquinas&quot;&gt;¿Cómo de inteligentes somos en conjunto los humanos y hasta dónde pueden llegar las máquinas?&lt;/h2&gt;

&lt;p&gt;Empecemos por el rango de inteligencias humanas. Porque para mí no existe una inteligencia humana, como ambos bandos asumen, sino muchas. Incluso dentro del, más o menos socialmente aceptado IQ, tenemos todo un rango donde las personas con un IQ de 70 o inferior se consideran dependientes ya que no pueden llevar una vida normal por sí solas, hasta las personas con IQ 150 o superior, que se consideran genios por encima del 99.9% de la población. (Aún así, estos individuos son, teóricamente, uno de cada 1000, con lo que solo en España debería haber varias decenas de miles de ellos…) Pero, claro está, no es todo el IQ. La situación socioeconómica y cultural, sus conexiones sociales y la suerte de ese individuo tienen mucho que decir en su futuro. Y vaya por delante, no siente más, ni es más, una persona con más IQ ni siente menos ni es menos una persona con menos IQ.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/iq_chart.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Además, como decía en el disclaimer del principio, uno puede ser un genio en matemáticas y a la vez ser disléxico, o sordo. Puedes tener oído perfecto pero nunca aprender a tocar un instrumento. Puedes ser muy bueno con los problemas lógicos y malo con los espaciales, etc., etc. La inteligencia tiene un millar de componentes diferentes que aún estamos aprendiendo a distinguir y que influyen, junto con la suerte y el entorno, en si una persona acaba siendo un premio Nobel o otro currito más.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/terence_tao_iq.png&quot; alt=&quot;Terence Tao has an IQ of 224&quot; /&gt;
Imagen que muestra dónde cae el &lt;a href=&quot;https://check-iq.org/celebrity-iq/terence-tao-iq&quot;&gt;IQ de Terence Tao dentro de la gráfica de IQ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pero ¿entonces qué? ¿Somos “el tope” de la inteligencia? Visto toda esta variación no parece que sea así. Parece más bien que hay muchas inteligencias y que unas serán mejores para ciertas tareas que otras.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/nTgeLEWr614?si=k3T5lOHnEmJxYz2Z&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Los animales no encajan en nuestros tests de IQ, pero sí demuestran inteligencia de muchas formas &lt;a href=&quot;https://www.ultimatekilimanjaro.com/the-15-smartest-animals-in-the-world/&quot;&gt;cada vez mejor documentadas&lt;/a&gt;. Hay registros de cuervos resolviendo rompecabezas, de chimpancés recordando grupos de números en un abrir y cerrar de ojos (en el video de arriba), de orcas organizando planes de caza complejos, simios usando herramientas, lenguajes y dialectos animales, y animales “bilingües” (que son capaces de entender dos dialectos de regiones diferentes cuando se les muda de una a otra)… Y eso son solo inteligencias que nosotros podemos apreciar. Cada vez está más claro que los animales no tienen el cerebro solo para llevarlo de un sitio para otro o para gestionar sus órganos internos, sino que muchos de ellos son capaces de recordar, planificar, reconocerse, orientarse o coordinarse a niveles que no comprendemos.&lt;/p&gt;

&lt;p&gt;Todo esto pinta una foto de la inteligencia mucho más rica y variada. La inteligencia no es un monolito, es más bien un conjunto de habilidades, agudezas, capacidades, conocimientos y competencias. Un chimpacé tiene más memoria de trabajo que nosotros y más agilidad, pero los chimpancés no han podido crear culturas y acumular conocimiento como nosotros. Una calculadora es órdenes de magnitud más rápida y fiable que el mejor ser humano haciendo aritmética o cálculo diferencial. Una base de datos es mucho más fiable, repetible y transparente que la memoria humana. Pero ambos carecen totalmente de agencia o de capacidad de interactuar con el mundo. Pero entonces, ¿qué puede hacer la IA? ¿Dónde cae en todo este espectro? ¿Hasta dónde llegará?&lt;/p&gt;

&lt;p&gt;Ese es el siguiente problema. Voy a intentar reflejar en un par de gráficos lo que yo veo cuando los miembros de uno y otro bando hablan del tema.&lt;/p&gt;

&lt;p&gt;Para mí, los humanistas ven algo así:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/humanista.jpg&quot; alt=&quot;Visión humanista del espectro de la inteligencia&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Para ellos la IA claramente nunca alcanzará a los humanos. Apenas es más inteligente que un reptil o un pájaro, aún no está al nivel de otros mamíferos, y quedan décadas, si no siglos, para que una máquina pueda parecerse suficientemente a un humano como para sacar el debate a la palestra. &lt;strong&gt;Lo que estamos haciendo con este debate es distraer al público de los problemas importantes actuales del aprendizaje automático, como los sesgos, la propiedad intelectual de los datos de entrenamiento o las personas discriminadas por estos sistemas o por no tener acceso a ellos&lt;/strong&gt; (todas preocupaciones totalmente legítimas pero que no son el foco de esta reflexión).&lt;/p&gt;

&lt;p&gt;Mientras que los trans-humanistas y doomers ven algo así:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/doomer.jpg&quot; alt=&quot;Visión doomer del espectro de la inteligencia&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Para ellos &lt;strong&gt;es evidente que la IA más temprano que tarde superará a las personas y entonces no habrá retorno. En poco tiempo alcanzará velocidad de escape, no entenderemos lo que hace ni sus motivos para hacerlo y estaremos bajo su merced o su bendición eterna&lt;/strong&gt;, según el sub-bando.&lt;/p&gt;

&lt;p&gt;De hecho, después de hacer ese gráfico, encontré este otro, que es un gráfico de Leopold Aschenbrenner, uno de los niños prodigios de OpenAI que ahora está creando su propia empresa sobre superinteligencia:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/intelligence_explosion.png&quot; alt=&quot;Gráfico extrapolando la explosión de inteligencia con márgenes de error&quot; /&gt;&lt;/p&gt;

&lt;p&gt;En su ensayo &lt;a href=&quot;https://situational-awareness.ai/from-agi-to-superintelligence/&quot;&gt;“La década siguiente”&lt;/a&gt; Aschenbrenner asegura que la ASI es inevitable y que la escalada tanto en energía como en dinero y recursos para conseguirla seguirá imparable sin darse con ningún muro físico, económico ni social…&lt;/p&gt;

&lt;h2 id=&quot;quién-tiene-razón&quot;&gt;¿Quién tiene razón?&lt;/h2&gt;

&lt;p&gt;Solo el tiempo lo dirá. Creo que esta gran diferencia de opiniones, a parte del puro interés personal, está una visión diferente de lo que nos hace humanos e inteligentes. Unos miran las habilidades donde las IAs cometen errores y dicen “¿véis? nunca serán como nosotros, no entienden lo que están haciendo” otros miran aquellas tareas en las que la IA destaca o sobrepasa a los humanos y dicen “¿veis? cuando sea así en todas las demás disciplinas será imparable”. Pero después de ver toda la variabilidad que hay en los humanos y los animales, y de años de trabajo de ingeniería yo me inclino a pensar que es una cuestión siempre de compromisos, mejorar cada habilidad tiene un coste, determinadas tareas requieren de uso herramientas concretas o de un contexto o de unos datos que la IA aún no ha visto… La gráfica, para mi, es en realidad algo así:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/inteligencia_star_chart.png&quot; alt=&quot;Visión intermedia&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Gŕafico generado con Google Gemini 2.5 pro (https://gemini.google.com/share/bb37aabfa351)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Es lo que Adrej Karpathy llamó &lt;a href=&quot;https://x.com/karpathy/status/1816531576228053133?lang=en&quot;&gt;“Jagged intelligence”&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La Inteligencia Artificial General, o por sus siglas en inglés: AGI, será algo que estará en medio de todo ese espectro de inteligencias que exhibimos los humanos. Unas serán buenas en matemáticas y otras en reconocer y hablar sobre enfermedades. Habrá AGIs que no podrán ser “autónomas” aunque tengan algún tipo de memoria persistente y agencia. Como niños a los que hay que cuidar.&lt;/p&gt;

&lt;p&gt;Incluso podríamos argumentar que sistemas actuales como GPT-4 o Claude 3.5 ya demuestran capacidades que superan a los humanos en ciertas áreas específicas (como el procesamiento de lenguaje o la recuperación de información), mientras que siguen siendo muy inferiores en otras (como el razonamiento causal o la comprensión del mundo físico). Los LLMs por si solos tienen muchos problemas y están lejos de tener la capacidad ejecutiva de un humano. No se les da bien planificar o ejecutar planes, no se les da bien razonar ni saber cuando realmente están respondiendo algo &lt;em&gt;“simplemente porque suena bien”&lt;/em&gt;. Todo esto se está intentando paliar con arquitecturas que incluyen memorias externas, reintentos, control del output para evitar respuestas inapropiadas o control del input para evitar jail-break. Pero esto indica que hay mucho trabajo por hacer. Personalmente creo que el camino a la ASI es mucho más largo de lo que se presume ahora mismo y que estaremos unos cuantos años en este limbo de AIs muy potentes en algunos aspectos y muy torpes en otros, que supondrán grandes mejoras en muchos campos como estamos viendo con AlphaFold o Copilot, pero no serán AGIs.&lt;/p&gt;

&lt;p&gt;Lo estamos viendo con los coches autónomos: ya conducen miles de kilómetros al día, pero sólo en ciudades concretas y en condiciones concretas, expandir esa red donde pueden operar con seguridad es un proceso lento porque cada ciudad y cada pais tiene diferente contexto.&lt;/p&gt;

&lt;p&gt;El propio Sam Altman en su famoso ensayo &lt;a href=&quot;https://ia.samaltman.com/&quot;&gt;“The intelligence Age”&lt;/a&gt; hablaba de ASI en “miles de días” una medida tan imprecisa como poco habitual. Miles de días podrían ser 3650 días (10 años), o podrían ser 9000 (~30 años) este ensayo debería haber &lt;em&gt;enfriado&lt;/em&gt; las espectativas del mercado enormemente, pero no fue así, grandes empresas siguen gastando miles de millones con la esperanza de que si siguen aumentando el tamaño de los modelos y los datasets los modelos seguirán mejorando sin tocar techo.&lt;/p&gt;

&lt;p&gt;La visión humanista no se equivoca en que los millones de años de evolución han conseguido sistemas increíblemente complejos, sofisticados y optimizados. La inteligencia es una ventaja evolutiva. Es lo que los doomers llaman un &lt;strong&gt;fin instrumental convergente: ser más inteligente es útil para conseguir muchas otras cosas, por lo tanto sea lo que sea que necesitas, ser más inteligente seguramente te ayude&lt;/strong&gt;. Esto es lo que hizo crecer el cerebro de los homínidos hasta donde nos encontramos ahora: la capacidad de coordinarnos, de planificar, de rastrear una presa o tenderle una trampa, de comunicar conceptos abstractos en forma de palabras y finalmente la capacidad de crear una cultura común que perdure durante generaciones fue una ventaja sobre los otros animales y los otros homínidos. El problema de los humanistas es pensar que nosotros somos el techo o que la IA nunca podrá llegar a donde estamos y sobrepasarnos en muchos aspectos.&lt;/p&gt;

&lt;p&gt;La realidad es que la inteligencia, tanto humana como artificial, es multidimensional, multisensorial y contextual. Un sistema puede ser extraordinariamente capaz en un dominio mientras es básico o incompetente en otro. Por eso me parece tan chocante la visión tanto de uno como el otro campo y no entiendo esta batalla argumentativa que no empieza por reconocer que es reduccionista al asumir que todos los humanos tenemos un sólo nivel de inteligencia y que todos estamos de acuerdo en lo que significa.&lt;/p&gt;

&lt;h2 id=&quot;actualización-04122025&quot;&gt;Actualización 04/12/2025&lt;/h2&gt;

&lt;p&gt;Blaise Agüera y Arcas toca este tema en sus charlas y en su libro “What is intelligence?” que es una teoría sobre cómo la vida y la inteligencia son computacionales, fundamentada en un montón de experimentos y en trabajos académicos. Es una locura y una maravilla de libro lo que llevo hasta ahora, increíblemente bien documentado y fundamentado, con cientos de referencias y además se puede leer online! https://whatisintelligence.antikythera.org/ El TLDR en su charlas por ejemplo en LongNow:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/KhSJuqDUJME?si=5RwI-XMA6gN0eMUa&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h2 id=&quot;referencias&quot;&gt;Referencias&lt;/h2&gt;

&lt;p&gt;Voy a añadir aquí al final algunos videos y enlaces más, además de los que he dejado salpicados por el artículo, para quien quiera seguir aprendiendo sobre estas dos visiones:&lt;/p&gt;

&lt;p&gt;Timnit Grebru, sobre AGI: nunca la he visto atacar la pregunta directamente, siempre la redirige a hablar de sesgos, discriminación, capitalismo, ética y el mercado laboral, para ella la AGI no tiene sentido como concepto y el mero hecho de planteárselo es un intento de evadir los problemas reales que tenemos ahora mismo:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/P7XT4TWLzJw?si=NZCdhmbeOWXKiQ6A&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Geoffrey Hinton dió una charla a principios de 2024 donde expone las razones por las que cree que la IA superará la inteligencia humana:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Es6yuMlyfPw?si=lavmHEBFhBbXGPaR&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Un video muy aclaratorio sobre AI ethics y el discurso que hay en este campo de ética vs riesgos de la IA es esta entrevista a Anca Dragan, responsable de seguridad en IA en Google Deepmind. Me gusta porque va desde los problemas éticos de decidir qué puede y qué no puede responder una IA (que sería parte del discurso de Timnit Gebru y los humanistas) hasta los problemas que puede presentar una IA con agencia para ejecutar acciones en el mundo en tu nombre o incluso de forma totalmente independiente (que es donde se centran los doomers) Me gusta mucho esta entrevista porque es un pequeño vistazo a todos los problemas que puede haber ahí detrás y puede verse claramente que esto no es un problema de blanco o negro, si no de un amplio espectro de problemas con una gran dificultad:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/ZXA2dmFxXmg?si=v5coVf0erTuK7b5k&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Sabine Hossenfelder es una física y divulgadora en youtube que escribe sobre temas difíciles como este, hace poco hizo un video sobre AI escaling y cómo es una inevitabilidad física que se de con un muro debido al llamado &lt;a href=&quot;https://en.wikipedia.org/wiki/Length_scale&quot;&gt;“decoupling of scales”&lt;/a&gt; Lo que significa que por mucho que mires cómo se comporta la materia a nivel macroscópico nunca podrás deducir que ocurre a nivel quántico. Esto según Abina aplica a muchos fenómenos, donde sin los datos y los instrumentos adecuados no puedes avanzar el conocimiento:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/AqwSZEQkknU?si=0cX78ai6_C1D0PlE&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;En la Navidad de 2024 OpenAI ha presentado un modelo que supera el benchmark Arc AGI, un benchmark que lleva en su nombre AGI y que François Chollet (que podríamos situar dentro del campo de los “humanistas” tal u como los he definido en este artículo) ha estado publicitando durante años como una prueba definitiva de generalización a la hora de resolver problemas. Creo que esto es un hito en el camino a la AGI y aunque el propio Chollet y otros humanistas ya estén empezando a mover la meta de nuevo y a declarar que necesitamos un benchmark mejor para medir la inteligencia, la verdad es que este era al que señalaban hasta ahora y este modelo de OpenAI demuestra que los modelos siguen saturando todos los benchmarks sin encontrar un muro real.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/SKBG1sqdyIU?si=KqgjwRooVN0yduuP&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Google ha publicado un modelo de capacidad parecida (gemini 2.5 pro experimental) y en las últimas entrevistas y declaraciones tanto Demis Hassabis
como David Silver han dejado claro que su intención es sobrepasar las capacidades humanas. Demis Hassabis ha declarado en varias ocasiones que AGI para él no es un modelo capaz de hacer lo que hace un humano medio, si no uno capaz de realizar tareas con la capacidad de “el mejor de los humanos” en cada campo. Es decir, alcanzar el nivel de AlphaGo, pero para cualquier tarea que pueda realizar una persona. Lo cual, para la mayoría de los expertos sería en realidad ASI (artificial super inteligence) En esta entrevista David Silver habla sobre esta idea y cómo en Google pretenden alcanzarla usando aprendizaje por refuerzo (Reinforcement Learning):&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/zzXyPGEtseI?si=TChWjhglUSiXBX9H&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

</content>
 </entry>
 
 <entry>
   <title>AI learnings compilation</title>
   <link href="http://juanmirod.github.io/2024/05/24/ai-learnings-compilation.html"/>
   <updated>2024-05-24T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2024/05/24/ai-learnings-compilation</id>
   <content type="html">&lt;p&gt;It’s been years since I am interested in AI, I read and I listen to podcasts and do some courses and learn to use APIs and models… but I am not working on AI (directly at least), I don’t have a CV or projects that I can show, I don’t have a real course, master or anything. I have decided to keep doing
it this way, because it is the way that works for me and motivates me, but I want to try to be more intentional and write down what I do and what I learn. This is an informal journal of those learnings,
maybe in the future I will decide to do some kind of curriculum, but this is good enough to start.&lt;/p&gt;

&lt;h2 id=&quot;learning-about-llms&quot;&gt;Learning about LLMs&lt;/h2&gt;

&lt;p&gt;To learn more about LLMs and embeddings’ models and how they really are trained and a little bit of the theory so I have a more complete understanding I am reading:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.llm-book.com/&quot;&gt;Hands-On Large Language Models&lt;/a&gt; - This book by Jay Alammar is a great step by step guide through the different types of models, their applications, how to use them and a bit of the theory. Complementary to the book there are a lot of resources linked in the book and created by Jay Alammar like &lt;a href=&quot;https://jalammar.github.io/illustrated-transformer/&quot;&gt;The ilustrated transformer&lt;/a&gt; or the course in Deeplearning &lt;a href=&quot;https://www.deeplearning.ai/short-courses/how-transformer-llms-work/&quot;&gt;How transformers work&lt;/a&gt;. I recommend all of them as this is a pretty dense topic and seeing it in different formats will help to digest it.&lt;/p&gt;

&lt;p&gt;In the same line but more code intensive it is really illustrative the video &lt;a href=&quot;https://www.youtube.com/watch?v=kCc8FmEb1nY&quot;&gt;Let’s build GPT&lt;/a&gt; by Andrej Karpathy. If you have no idea of Pytorch I recommend reading first the &lt;a href=&quot;https://docs.pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html&quot;&gt;60 minutes blitz to pytorch&lt;/a&gt; and playing a bit with the examples or even continue with the pytorch tutorials. That way you will understand much better the code that Karpathy explains in the video.
(One thing to take into account with Karpathy’s video is that he explains how to build a GPT, which is a Decoder and then the attention layer is masked, this does not happens with encoders, and the transformer paper uses both encoder and decoder because it was a paper about language translation. He explains this at the end of the attention part.)&lt;/p&gt;

&lt;p&gt;And another complementary material is the &lt;a href=&quot;https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi&quot;&gt;playlist in 3Blue1Brown about neural networks&lt;/a&gt; it is great to have a visual explanation and a better mental model of what a neural network is, how it works conceptually and mathematically and bottom up, from an example with a couple of layers of NN to transformers and attention.&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;video-recommendationsreviews&quot;&gt;Video recommendations/reviews&lt;/h1&gt;

&lt;h2 id=&quot;geoffrey-hinton&quot;&gt;Geoffrey Hinton&lt;/h2&gt;

&lt;p&gt;I watched the other day an interview to Geoffrey Hinton, it’s interesting to listen to him because he has a lot of perspective from many years of experience and working with a lot of people, the interview is:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/n4IQOBka8bc?si=o84QL6sc_eTdXqf_&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;My key insights from the interview:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;He also (as Sam and Ilya) thinks that more scale produces more intelligence, clever algorithms are nice thought experiments, but they are probably not needed.&lt;/li&gt;
  &lt;li&gt;Things he would add to current models:
    &lt;ul&gt;
      &lt;li&gt;More time scales for learning (he says we only have two because we only have training and zero-shot or context, but IMO we have three scales: pre-training, post-training: RLHF or instruction tunning…) and context&lt;/li&gt;
      &lt;li&gt;A way for the model to “reason” about something and learn from the reasoning, he is referring to some kind of RL for LLMs.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Digital computation is much more powerful because it scales better and it is repeatable, analogical computation, even artificial one, is not repeatable because the same weights won’t work in another analogical computer.&lt;/li&gt;
  &lt;li&gt;Chomsky is wrong: language is not innate, general learning processes can produce and understand language. (this is practically a consensus in computer science circles now, but still very controversial in linguistics circles where Chomsky is the father of the field).&lt;/li&gt;
  &lt;li&gt;About choosing people and problems: follow your gut, there are people that you see that “get it” and people that you see that think outside the box, similarly with the problems, sometimes something doesn’t fit and you have to double down there… I think his intuitions are good because he is very intelligent himself, this advice may not apply to everyone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;He of course has lots of interviews an talks since he leaved Google, I may add some others if I find them interesting.&lt;/p&gt;

&lt;h2 id=&quot;peter-norvig&quot;&gt;Peter Norvig&lt;/h2&gt;

&lt;p&gt;A talk and some questions for Peter Norvig about the future of programming combined with LLMs&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/ia6aJIplmtc?si=0xnBr7VehBR3hN_A&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Insights from the interview:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I agree with most of what Norvig says about hybrid systems and combining LLMs with tools, formal languages and Knowledge bases, that is the way it is
definitely taking some months later and I think we still need to see more developments around that. Cohere also advocates for tool use to give more agency to LLMs and I think that is OpenAI will be doing with GPT-5.&lt;/li&gt;
  &lt;li&gt;This is the pytude he talks about that uses word embeddings and PALM-2: &lt;a href=&quot;https://github.com/norvig/pytudes/blob/893b4aa82abe5d6c5b0f6c4082501c2694df724c/ipynb/OneLetterOff.ipynb#L503&quot;&gt;https://github.com/norvig/pytudes/blob/893b4aa82abe5d6c5b0f6c4082501c2694df724c/ipynb/OneLetterOff.ipynb#L503&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;About fairness and errors, I think he also is very sensible: we are giving more difficult problems to this systems and expecting them to do it better than ourselves. First we need to define what we mean by fairness, then we need to implement that, and any implementation it is going to prioritize some people over other because time and effort is limited and we need to put that time and effort into features somewhat sequentially.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;gary-marcus&quot;&gt;Gary Marcus&lt;/h2&gt;

&lt;p&gt;To level a bit the hype, a keynote from Gary Marcus in AGI24, where he talks about the pitfalls of the transformer frenzy and the scaling laws. He even predicts that we are in the edge of a new IA winter because GenAI is not delivering enough value to compensate the huge amounts of money spend in training in the last years (OpenAI is the most notable example, because they have made it to several economics newspapers lately because it is claimed that they lost $5B last year, but he also talks about Mustafa Suleyman or Dario Amodei leaving as a sign of this coming buble burst or disinvestment wave or however you want to call it)&lt;/p&gt;

&lt;p&gt;Gary Marcus is considered a “doomer” and he has an unusually hard and moderate view on the state of AI. To me, even if we have a disinvestment wave in GenAI and people stop trying to train bigger and bigger LLMs models, we still have to discover a lot of uses for the LLMs that we have. We are lucky to have open models like LLAMA3 and comman-r and others that can be really useful in many tasks even if they don’t deliver on the promise of AGI or agentic AI, and we still have a good decade ahead discovering new applications of LLMs and integrating them on a lot of tools, making them faster, smaller, more efficient and more useful…&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/91SK90SahHc?si=FJjtm8qUb13ORazD&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h1 id=&quot;jodie-burchell&quot;&gt;Jodie Burchell&lt;/h1&gt;

&lt;p&gt;This talk by Jodie Burchell is really an amazingly well delivered summary of the evolution of ML until now, how LLMs work, when they work best and a skeptic view on AGI and ASI, very well defended. She finishes with how to use them with a sample RAG application in a notebook. She also has the notebook and all the references from the talk &lt;a href=&quot;https://github.com/t-redactyl/simple-rag-document-qa/tree/main&quot;&gt;in this repo&lt;/a&gt;&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Pv0cfsastFs?si=Vlx0i5TpF226AOQm&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h1 id=&quot;andrej-karpathy&quot;&gt;Andrej Karpathy&lt;/h1&gt;

&lt;p&gt;Great talk from Andrej Karpathy about the evolution in software in the last years&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/LCEmiRjPEtQ?si=tLKYTCf8s1HvE2aU&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;&lt;strong&gt;Key insights for me:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;This is decade of agents, not the year, it’s going to take time to integrate them (think Waymo)&lt;/li&gt;
  &lt;li&gt;Models ate part of the software stack: tasks that required lots of code are now done with a call to a model.&lt;/li&gt;
  &lt;li&gt;Prompt/context is like programming the models, but in plain English.&lt;/li&gt;
  &lt;li&gt;We need to keep humans in the loop (and agents on a leash) and build tools that allow this loop to be faster and easier (like Cursor)&lt;/li&gt;
  &lt;li&gt;We are still building the Ironman suit, we can’t pretend we can build completely autonomous robots (yet)&lt;/li&gt;
  &lt;li&gt;GUIs are still highly valuable for humans&lt;/li&gt;
  &lt;li&gt;Markdown documentation and tools like MCP for agents&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;laura-tacho&quot;&gt;Laura Tacho&lt;/h1&gt;

&lt;p&gt;Measuring the impact of AI on software engineering – with Laura Tacho&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/xHHlhoRC8W4?si=3UPwtoDEuR2qxVxc&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;To me this conversation validates some things I have experience myself and talk about:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The productivity improvements is not in lines of code, typing speed never was the bottleneck.&lt;/li&gt;
  &lt;li&gt;But they see compounding improvements in DevEx, complexity of the tasks that one developer can accomplish and in other tasks like inspecting stack traces, debugging, understanding the code or doing big refactors.&lt;/li&gt;
  &lt;li&gt;Documenting is good for humans and for AI, but documentation has to be optimized for AI (code examples instead of screenshots, programatic ways to do things instead of GUI’s How To)&lt;/li&gt;
  &lt;li&gt;Adoption is important, having the tools and licenses for everyone is important to get everyone on board and not only the early adopters.&lt;/li&gt;
  &lt;li&gt;AI is good at tasks with a lot of structure like YAML config files, unit tests and refactoring, no so good at “frontier” work where there is not many examples or any line of code counts.&lt;/li&gt;
  &lt;li&gt;When writing code is cheaper, you end up doing more of the rest of the job: alignment, meetings, design, monitoring, gathering feedback… so the future looks like more like product engineering and less like all day coding.&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>IA y trabajo</title>
   <link href="http://juanmirod.github.io/2024/04/23/ia-y-trabajo.html"/>
   <updated>2024-04-23T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2024/04/23/ia-y-trabajo</id>
   <content type="html">&lt;p&gt;Últimamente veo una tendencia en las charlas y podcasts que escucho. Se puede resumir muy rápido y es una
de esas cosas que una vez las has visto no puedes dejar de verla: todo el mundo dice &lt;strong&gt;“La IA no nos va a quitar el trabajo, va a crear nuevos empleos que no podemos predecir, pero eso que están haciendo con IA en MI trabajo me parece muy mal.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/writer_and_robot.jpeg&quot; alt=&quot;&amp;quot;A writer looking skeptically at a robot that is writing a book&amp;quot; DALL-E 3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Es algo muy humano, cuando alguien nos viene diciendo &lt;em&gt;“tengo miedo de que la IA me quite el trabajo”&lt;/em&gt; le quitamos
importancia y decimos &lt;em&gt;“no, que va, ahora vas a ser más productivo, o podrás estar más tiempo con tu familia”&lt;/em&gt; (como si las empresas fueran a cedernos ese tiempo de buena gana porque ahora somos más productivos…) Pero sin embargo, cuando vemos que un avance de IA de repente puede hacer parte de nuestro trabajo tan bien como nosotros, pero además más rápido y por una fracción del coste, nos empezamos a poner nerviosos y defensivos y decimos que eso no es ético.&lt;/p&gt;

&lt;p&gt;No quiero señalar a nadie, así que no diré nombres, pero recientemente oyendo un podcast esto fue muy evidente para mí. Entrevistaban a alguien que daba cursos sobre IA y que es evangelista sobre el tema, con lo que por supuesto todo era positivo, &lt;em&gt;“tenemos que abrazar la IA y aprovechar todas las bondades que tiene”&lt;/em&gt;. Pero en cuanto los entrevistadores llegaron al ejemplo de los deep fakes de audio y video donde un modelo puede generar una versión totalmente convincente de audio o incluso un avatar que pueda dar las lecciones con tu imagen y tu voz, eso ya no le pareció tan maravilloso y justo en ese punto abogaba por regulación y la prohibición de este tipo de contenidos, respetando la PI y del Copyright (mira por donde).&lt;/p&gt;

&lt;p&gt;Me parece increíblemente ingenuo o hipócrita este juego y lo veo repetido una y otra vez: Periodistas que dicen que la IA es el futuro, pero que no puede usarse en los periódicos porque no contrasta la verdad o no entiende lo que es real de lo que no (como si todos lo hicieran). Músicos que dicen que la IA les permite usar las redes sociales y gestionar sus campañas como nunca antes, pero que lo de hacer música hay que regularlo. Diseñadores que la usan para hacer juegos y ayudarles con el código, pero lo de generar imágenes es una tontería porque las imágenes no tienen alma o son un crimen porque la IA está copiando. Devs que creen que copilot no es para tanto pero que generan imágenes y videos o música con IA…&lt;/p&gt;

&lt;p&gt;La lista no acaba nunca y creo que el patrón va quedando claro: todos pensamos que lo que hacemos nosotros es especial, es difícil y nunca podrá hacerlo un ordenador, pero cuando es el trabajo de otra persona que no conocemos tanto, entonces sí que vemos la ventaja que ofrece.&lt;/p&gt;

&lt;p&gt;Creo que es una trampa mental que dice más de nuestros sesgos que de la IA y que es lo que hace ese mensaje de “la IA no va a quitar empleo, los transformará y creará empleos nuevos” tan popular y fácil de aceptar.&lt;/p&gt;

&lt;p&gt;Es fácil ver todas las complicaciones y detalles y toda la profundidad y aprendizaje que tiene nuestro propio trabajo. Yo mismo pienso todos los años que llevo programando y aprendiendo, cómo cada tarea implica comprender el problema, modificar varios ficheros, crear tests, documentación, hablar con personas, clarificar las especificaciones: no es fácil. Pero eso mismo es lo que ve un diseñador o lo que ve un músico o un médico o un abogado: no es fácil reemplazarnos, o eso pensamos.&lt;/p&gt;

&lt;p&gt;Sin embargo, para mí, las imágenes que genero con DALL-E 3 o con LeonardoAI o con Midjourney son mucho mejores de lo que yo podría hacer con un programa de edición digital aunque le dedicara horas o días. Lo mismo siente alguien que programa preguntando a ChatGPT o alguien que genera música con Udio. Es decir la IA &lt;strong&gt;ya es mejor que la media en una enorme cantidad de tareas&lt;/strong&gt; no es tan buena programando como yo, o tan buena diseñando como mi hermano, pero es MUCHO MEJOR que una persona que no sepa hacer esas cosas.&lt;/p&gt;

&lt;p&gt;Si lo ponemos todo junto. Si nos separamos un momento de nuestro ego y nuestro orgullo por todo lo que sabemos y hemos conseguido. Si vemos el avance que se está produciendo en todos los campos, en la palabra escrita, en el diseño, en robótica, en planificación, en música, en empatía, en comprensión, traducción, el acceso a los datos y al conocimiento…Si somos sinceros con todo lo que está pasando ¿Qué nos queda?&lt;/p&gt;

&lt;p&gt;Si hoy tenemos sistemas que están democratizando la creación digital como nunca antes y cualquiera puede programar, diseñar o crear música, si cualquiera puede escribir, hacer videos de stop motion o animación, generar avatares indistinguibles de una persona real, generar anuncios, series, etc. ¿Qué vamos a hacer los humanos que no puedan hacer las máquinas por nosotros o que no requiera 100 veces menos esfuerzo y personal?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Todo esto llevará años,&lt;/strong&gt; conectar y automatizar todas esas tareas no es fácil, y al menos al principio, serán necesarias personas que controlen todas estas herramientas semi autónomas. No soy de esas personas que piensan que el año que viene vayamos a tener todos los problemas resueltos. Pero dentro de 10 años, ¿de verdad pensamos que no podremos generar programas, películas, música o básicamente generar cualquier contenido digital o automatizar cualquier tarea mediante instrucciones en lenguaje natural? ¿Y eso no implica reducir drásticamente la cantidad de trabajo que puede hacer un humano pero no una máquina? ¿De verdad pensamos que hay tanta demanda como para cubrir toda esa productividad extra? ¿Hasta cuando?&lt;/p&gt;

&lt;p&gt;Voy a intentar hacer el ejercicio mental de pensar qué labores podría hacer una IA con el trabajo que conozco, el de desarrollador:&lt;/p&gt;

&lt;p&gt;Recientemente se hizo bastante eco la &lt;a href=&quot;https://www.cognition-labs.com/introducing-devin&quot;&gt;publicación de un programa agente llamado Devin&lt;/a&gt; que según Cognition, la empresa que lo ha creado, fue capaz de completar el 13.86% de las tareas de un benchmark de &lt;em&gt;“tareas que realiza un ingeniero de software”&lt;/em&gt; (en realidad el 13.86% de un 25% de esas tareas seleccionadas aleatoriamente, me viene a la cabeza la pregunta de cuántas veces seleccionaron “aleatoriamente” tareas y ejecutaron el modelo sobre ellas)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/devin.png&quot; alt=&quot;Gráfica sobre la comparación de los resultados de Devin en relación a varios LLMs en el benchmark SWE&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Por supuesto, estas tareas son un subset escogido de github con unos requisitos bastante altos de que estén bien definidas, se hayan cerrado exitosamente con una sola MR, etc. En concreto el benchmark utilizado fue &lt;a href=&quot;https://huggingface.co/datasets/princeton-nlp/SWE-bench&quot;&gt;SWE-bench&lt;/a&gt; que contiene issues de 19 proyectos seleccionados de python. El dataset incluye una descripción del problema, el commit del estado del repositorio cuando se creó ese issue y el patch de la solución. Con lo que los problemas están realmente acotados a bugfixes o pequeñas features bien definidas en proyectos con un recorrido y donde no hay que navegar varias herramientas o fuentes de datos para resolver el problema. Vamos a ampliar un poco el problema a algo más parecido a lo que es realizar una tarea de desarrollo normal:&lt;/p&gt;

&lt;p&gt;Podemos dividir el trabajo de desarrollador en varias tareas de alto nivel:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Entender las especificaciones.&lt;/strong&gt; Esto es más complicado de lo que parece porque normalmente las especificaciones son incompletas y no es suficiente con “entenderlas” también hay que rellenar los huecos. Esta es una de las cosas que más resaltan los programadores cuando dicen que una IA nunca los sustituirá, pero para mí es como lo de la creatividad y las imágenes sin alma: los llms actuales ya muestran una capacidad bastante buena de entender especificaciones e incluso rellenar los huecos con comportamientos esperados. Es el típico ejemplo de “hazme una web que muestre un cubo en 3D dando vueltas en medio de la pantalla” y ChatGPT sabrá que tiene que usar Threejs, seguramente elija también React si no le decimos lo contrario e incluso puede que añada él solo los controles para mover el cubo con el ratón.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Plantear una solución válida para el problema.&lt;/strong&gt; Como es lógico, cuanto más grande y complicado es el problema, más compleja es la solución. Esto es especialmente cierto en productos y servicios que llevan años funcionando y para los que hay que tener en cuenta un millar de situaciones que ya manejan, condiciones de proveedores, de la infraestructura, expectativas de los usuarios, etc. Para mí este es el problema más difícil de resolver con una IA general, más bien necesitaríamos una IA fine tuneada para nuestro producto y nuestra empresa, que pudiera acceder a las mismas bases de datos y herramientas que usan los desarrolladores y seguramente también a Jira y a otras herramientas de gestión de proyecto. Estamos muy lejos de esto, ahora mismo hay que dar el problema muy &lt;strong&gt;mascado&lt;/strong&gt; y acotado para que los LLMs actuales puedan hacer algo útil.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Programar la solución y los tests automáticos que comprueban que realmente la aplicación cumple con las especificaciones.&lt;/strong&gt; Al final es la parte más fácil de la tarea: una vez están claras las especificaciones, el contexto, el alcance y cómo debe implementarse, solo queda picar código. Aquí es donde más ayudan los llms actuales como copilot o chatgpt, por ahora dirigidos por el desarrollador, aunque poco a poco vamos viendo soluciones de agentes más capaces.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Desplegar la solución.&lt;/strong&gt; Esto también puede variar enormemente dependiendo de la infraestructura que tenga nuestra empresa y nuestro proyecto, puede que tengamos un pipeline de integración continua, puede que tengamos que ejecutar algunos pasos o comandos manuales, puede que incluso tengamos que modificar la base de datos o usar algún tipo de gestor de hosting. Dependiendo de cómo de automatizado esté el proceso la IA podrá hacerlo o no, pero es un problema totalmente resoluble.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Debugging and Bugfixing.&lt;/strong&gt; Por muy buen programador que seas y aunque uses las mejores prácticas disponibles, al final siempre habrá algún defecto o bug que resolver: cambios en las especificaciones, casos no contemplados, errores no esperados, comportamientos del usuario que provocan inconsistencias, siempre hay algo que arreglar. Y para eso hay que ser capaz de reproducir el error, entender lo que está pasando y cómo arreglarlo en el código e idealmente escribir un test automático que lo reproduzca para luego arreglarlo en el código. Una vez hecho todo lo anterior el último paso seguramente sea el más sencillo y el que tal vez pueda hacer la IA pronto, aunque hasta ahora tampoco ha demostrado mucha habilidad en este punto.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hay muchas más tareas, más técnicas, de refactoring, de arquitectura, etc. Pero tampoco le veo sentido a definirlas todas, estas serían las tareas básicas de desarrollo de una nueva funcionalidad. En resumen, creo que es complicado y que tardaremos aún unos años en poder “enchufar” una IA como Devin a nuestro proyecto y que empiece a consumir tickets de Jira o issues de Github y producir MRs/PRs. Será algo progresivo, donde cada vez tendremos más IAs y haciendo más tareas que hasta ahora requerían cierto grado de “entendimiento” o “creatividad” sea como sea que queremos definir esos términos.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/scrum_robot.jpeg&quot; alt=&quot;&amp;quot;robot in an office in front of a scrum board looking at the board and deciding what task to take next pixel art&amp;quot; DALL-E 3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Aun así, no veo ningún motivo por el que las máquinas no podrían hacer todas estas tareas con el suficiente trabajo previo de conectarlas a las fuentes y herramientas adecuadas y de automatizar procesos. Supongamos que en 5 o 10 años tenemos sistemas capaces de hacer esto, siempre que se les prepare lo suficiente el terreno, y que tal vez sean capaces de resolver el 10% o el 20% de las tareas del backlog automáticamente, y otro tanto con ayuda. O que nuestro trabajo irá pivotando más a crear esas especificaciones para la IA.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ya pasamos una gran parte de nuestro trabajo desarrollando automatizaciones, tests, entornos de CI/CD que sabemos que nos permiten trabajar más rápido y con más calidad. Integrar IAs en todos estos procesos se verá como una extensión natural, como el siguiente paso en reducir el boilerplate y automatizar tareas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Imaginemos que todos los proyectos acabarán siendo algo parecido a este dataset de SWE-bench: Tienes un proyecto con su suite de tests y el sistema de CD/CI configurado, tienes un bot que está pendiente de las tareas que se crean en el proyecto y si creas una tarea lo suficientemente acotada y bien definida, el bot se la asigna, genera una MR y envía una notificación para que alguien la revise. Todo eso en pocos minutos desde que se creó la tarea. Si esto existiera, lógicamente se crearía un nuevo tipo de desarrollador centrado en definir estas tareas para la IA y revisar sus soluciones. Una especie de TDD donde sólo escribes especificaciones, lo demás lo hace la IA. Por la experiencia con copilot, incluso muchas de las soluciones que no fueran perfectas se podrían usar de punto de partida para resolver la tarea, una vez la IA ha localizado el punto del cambio, ha escrito el test y el código, es fácil hacer pequeñas correcciones de estilo o “deslices” y terminar la MR.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Todos esos serían avances increíbles y necesarios, porque la demanda de software de la sociedad actual es enorme. En el caso del software, así como en el de la medicina o la justicia, creo que hay una enorme demanda por destapar que dará trabajo aun por algunas décadas a IAs y humanos sin problema.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pero me parece terriblemente ingenuo pensar que toda esa productividad extra la vamos a poder aprovechar en estar con nuestra familia o en “pensar en problemas de más alto nivel” en lugar de simplemente acelerar la rueda de hamster del capitalismo. Creo que es algo que todos los trabajadores debemos empezar a pensar, en cómo vamos a adaptarnos a este cambio y cómo vamos a pedir que ese cambio sea justo y reduzca, en lugar de seguir aumentando, la desigualdad. Que se reduzca la jornada laboral o que las IAs y los datacenters paguen impuestos especiales, por ejemplo, hay muchas ideas ahí fuera. Pero la idea central es que esa productividad y esos beneficios no sean sólo para unos cuantos. Que todos nos beneficiemos de los avances de la IA, no sólo como consumidores, sino como parte del cambio y del progreso en calidad de vida, que es una tendencia que se ha visto frenada desde los 90 con la congelación de los salarios y el aumento de las ganancias del capital que ha llevado a un aumento de la desigualdad y que si no hacemos algo seguirá aumentando incluso a mayor velocidad gracias a todos estos avances.&lt;/p&gt;

&lt;p&gt;Así que mi conclusión a todo este tema es: no seamos ingenuos, no digamos que &lt;em&gt;“la IA va a generar muchos trabajos pero que el mío no lo toquen”&lt;/em&gt;. La razón por la que se crean estas herramientas es para automatizar tareas, aumentar la productividad y reducir las necesidades de contratación, es así, pero es que eso es lo que hacemos los ingenieros de software desde siempre, &lt;a href=&quot;http://juanmirod.github.io/2017/09/13/desarrollo-automatico.html&quot;&gt;lo llevo diciendo años&lt;/a&gt;. Las nuevas IAs generativas y los agentes que están a la vuelta de la esquina son una vuelta de tuerca más en esta tendencia exponencial. Sabemos que va a afectar a todos los trabajos en mayor o menor medida, sabemos que va a suponer un gran aumento de productividad y posiblemente acceder a problemas que antes nos parecían imposibles o demasiado costosos para merecer la pena, así que empecemos a pensar en cómo queremos que eso nos repercuta.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Repaso LLMs un año después</title>
   <link href="http://juanmirod.github.io/2023/11/02/llms-review.html"/>
   <updated>2023-11-02T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2023/11/02/llms-review</id>
   <content type="html">&lt;p&gt;Hace casi un año desde que ChatGPT nos volara la cabeza a todos. Ahora que las aguas se han enfriado un poco creo que es buen momento de hacer repaso y volver a evaluar dónde estamos y qué puede deparar el futuro.&lt;/p&gt;

&lt;p&gt;Para empezar diré que en mi post de hace 9 meses parece que no iba muy desencaminado. En marzo el hype por ChatGPT y GPT-4 era muy fuerte, todo el mundo hablaba de eso y Sam Altman dio muchas entrevistas siempre hablando de AGI y del futuro maravilloso que nos esperaba con esta nueva inteligencia. Ya deberíamos estar acostumbrados a que los gurús de Sillicon Valley siempre exageran, y casi un año depués no parece que estemos mucho más cerca de tener AGI que hace unos meses, pero sí que se han añadido un montón de funcionalidades a GPT-4 que lo hacen una herramienta muy potente y muy interesante. La multimodalidad, code-interpreter, Dalle-3 los plugins, acceso a la web… Hoy en día puedes darle una url a GPT-4 y hacerle preguntas sobre ella, puedes decirle que busque en google o la wikipedia, hacerle preguntas sobre una imagen e incluso pedirle que te genere una imagen y pedirle cambios en la misma conversación.&lt;/p&gt;

&lt;p&gt;Al mismo tiempo muchas empresas se han puesto las pilas, yo diría que en un tiempo record y nunca visto hasta ahora, casi todas las empresas grandes y las no tan grandes se han subido al carro y añadido funcionalidades con LLMs y generadores de imágenes: Adobe, Microsoft, Google, O’Relly, Canva, Notion, Honeycomb, etc. tienen integraciones en sus herramientas y el que más y el que menos tiene un asistente en su web o su app usando la API de ChatGPT. Ha sido un año bastante salvaje en cuando a actualizaciones y todo el mundo hablando de AI, aunque el mundo sigue girando y no parece haber hordas de personas que hayan perdido su empleo enfadadas, al menos por ahora.&lt;/p&gt;

&lt;p&gt;Para hacer un poco repaso personal de todo lo que he visto/oído/leído sobre el tema, voy a intentar recopilar aquí una lista de los podcast, videos y artículos que me han parecido más interesantes y de cómo encaja en el análisis de la situación.&lt;/p&gt;

&lt;p&gt;No me atrevo a dar una predicción de qué va a pasar exactamente, pero sí puedo apuntar un poco cuales me parecen más realistas y más centrados en soluciones y problemas actuales que podrían ser interesantes para cualquiera interesado en el tema. Hoy en día hay muchísimo ruido de gente vendiendo humo o diciendo obviedades durante 10 minutos para rellenar un vídeo. Me gusta mantenerme alejado de ese contenido que lo único que busca es crear hype o generar tráfico, no aporta nada y es fácil caer en la “fatiga informativa” intentado separar el grano de la paja.&lt;/p&gt;

&lt;p&gt;En cuanto a videos independientes sobre LLMs, me gustó mucho para sentar las bases el video que hizo Jeremy Howard: &lt;a href=&quot;https://www.youtube.com/watch?v=jkrNMKz9pWU&quot;&gt;A hackers guide to LLMs&lt;/a&gt; y también esta charla a la que llegué de casualidad por usa sugerencia de Youtube pero que me pareció muy certera en cuando al análisis de cómo puede evolucionar la arquitectura de los sistemas con LLMs: &lt;a href=&quot;https://www.youtube.com/watch?v=KVDKWrsP3es&quot;&gt;Are LLMs the beginning or end or NLP&lt;/a&gt; Otro video que me gustó mucho para dar un poco de perspectiva y muy alejado del hype es el de &lt;a href=&quot;https://www.youtube.com/watch?v=viJt_DXTfwA&quot;&gt;Robert Myles en Computerfile&lt;/a&gt; y para dar aún más perspectiva también está bien ver &lt;a href=&quot;https://www.youtube.com/watch?v=_8yVOC4ciXc&amp;amp;t=1s&quot;&gt;el que hicieron hace algo más de tiempo sobre GPT3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dos podcasts que siempre me aportan y me gusta seguir de cerca son Data Skeptic y MLST:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Data Skeptic ha sacado una serie de podcasts sobre LLMs: &lt;a href=&quot;https://dataskeptic.com/episodes/machine-intelligence&quot;&gt;Data Skeptic Machine Intelligence&lt;/a&gt; en las que habla con investigadores que están haciendo normalmente su tesis en temas relacionados con LLMs, tanto deployment, como fine tunning, aplicaciones, etc… En general temas muy centrados, nada de vender humo y que añaden profundidad y detalle a todo el tema.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.youtube.com/@MachineLearningStreetTalk&quot;&gt;Machine Learning Street Talk&lt;/a&gt; ha conseguido posicionarse como un referente en el sector y muchos de los nombres más conocidos del campo de ML han ido a entrevistas a su podcast. Tim Scarfe se ve que se empapa del tema y sabe de lo que habla y hace preguntas muy interesantes a la vez que mantiene un buen ritmo.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Mi experiencia en NLP</title>
   <link href="http://juanmirod.github.io/2023/07/07/mi-experiencia-nlp.html"/>
   <updated>2023-07-07T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2023/07/07/mi-experiencia-nlp</id>
   <content type="html">&lt;figure&gt;
    &lt;img src=&quot;/public/img/med-badr-chemmaoui-ZSPBhokqDMc-unsplash.jpg&quot; alt=&quot;An image of a block with some wireframes and a pen&quot; /&gt;
    &lt;figcaption&gt;Photo by &lt;a href=&quot;https://unsplash.com/@medbadrc?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Med Badr  Chemmaoui&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/ZSPBhokqDMc?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Hace tiempo que quiero contar esta historia bien contada y creo que es ahora o nunca. Mi experiencia personal con el NLP tiene varios años y creo que explica por qué me ha interesado tanto ChatGPT y por qué creo que esta tecnología tiene tanto potencial. Pero empecemos por el principio:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Warning! tengo muy mala memoria, cualquier parecido con la realidad será casi accidental, voy a tratar de resumir varios años de trabajo a grosomodo en un post por dejar constancia de mi viaje y por ordenar un poco mis pensamientos, pero como todo este blog, es público por si a alguien más le puede servir.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alrededor de 2017 empecé a trabajar en una empresa en un proyecto de NLP casi por casualidad. Yo había trabajado hasta ese momento fundamentalmente con la web, haciendo aplicaciones, juegos, pequeñas webs corporativas, campañas de publicidad… nada demasiado sofisticado y eso si casi siempre trabajando como único desarrollador, lo que llaman ahora un “full stack”: yo hacía el backend, la base de datos, las migraciones, la administración de sistemas y el frontend. Sólo me faltaba hacer los diseños.&lt;/p&gt;

&lt;p&gt;A esta empresa y su forma de trabajar le encajó bastante, porque aunque había varios desarrolladores, cada uno trabajábamos de forma independiente en nuestro proyecto, en nuestra oficina personal. En este caso la infra no había que gestionarla (oh yeah) pero todo lo demás sí. Incluso, en mi caso, la planificación del proyecto y la gran mayoría de las decisiones caían de mi parte. Digamos que era una especie de investigación y desarrollo muy aplicado, sin ser yo investigador y sin publicar nada, pero sí que un royo bastante libre de “tienes que hacer esto y tú te apañas el cómo lo consigues”&lt;/p&gt;

&lt;p&gt;La tarea por aquel entonces ya empezaba a estar de moda pero aun todo lo que había era muy tosco: programar un asistente virtual. Google tenía Home, Amazon Alexa, iPhone a Siri, no es que fueran super útiles, pero ahí estaban. Y muchas empresas se embarcaron en la tarea de tener su propio chatbot, aunque no tenían muy claro cómo se hacía eso.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/chatbot.png&quot; alt=&quot;A 3d render of a virtual robot on top of a phone - generated with Ideogram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;En mi caso, al tener mucha libertad y tiempo para desarrollar (no había prácticamente reuniones ni necesidad de coordinación) me empecé a meter en el mundo NLP y en cómo programar un Chatbot.&lt;/p&gt;

&lt;p&gt;Empecé por atacarlo por donde sabía. En aquel entonces ya se empezaba a hablar de los modelos de lenguaje, pero yo no tenía ni idea de ML ni recursos para aprender o contratar a nadie, así que por el momento descarté ese camino y fui investigando sobre lenguajes, sistemas expertos, NLP clásico…&lt;/p&gt;

&lt;p&gt;Así llegué a &lt;a href=&quot;https://github.com/ChatScript/ChatScript&quot;&gt;ChatScript&lt;/a&gt;, que es un lenguaje a medida diseñado y creado por &lt;a href=&quot;https://en.wikipedia.org/wiki/Bruce_Wilcox&quot;&gt;Bruce Wilcox&lt;/a&gt;, para programar chatbots. La verdad es que me pareció lo mejor que había en la época. En ese momento la mayoría de la gente usaba o bien &lt;a href=&quot;https://en.wikipedia.org/wiki/Artificial_Intelligence_Markup_Language&quot;&gt;AIML&lt;/a&gt;, un lenguaje anterior parecido pero basado en XML que era un horror (pero con el que estaba programado el chatbot más famoso y exitoso hasta el momento y que sigue en activo: &lt;a href=&quot;https://en.wikipedia.org/wiki/Kuki_AI&quot;&gt;Mitsuku&lt;/a&gt;), ChatScript (con el que Bruce Wilcox había ganado varias veces el premio Loebner y creo que había desarrollado trabajando en Telltale games como motor conversacional de sus aventuras) o python+NLTLK+spacy, que en el momento permitía tokenizar el texto de entrada y luego crear un montón de reglas por palabras, por frases, por entity detection etc, que al final se parecían bastante a ChatScript, pero eran bastante más feas de escribir y de entender y probar. Además ChatScript era infinitamente más rápido (daba la respuesta en milisegundos y era un servidor independiente muy fácil de hacer deploy y con una API muy simple) y ya traía un montón de reglas de uso general y algunos ejemplos de agentes… Así que me decidí por ChatScript.&lt;/p&gt;

&lt;p&gt;Encima de ChatScript pude hacer bastantes cositas. Llegué a hacer un interface gráfico que permitía crear chatbots sin que el usuario tuviera ni idea de programar, que luego compilaba a ChatScript, generalizando los ejemplos del usuario y que permitía probar y debugar tus conversaciones. Es decir era un &lt;a href=&quot;https://www.martinfowler.com/bliki/ProjectionalEditing.html&quot;&gt;Proyectional editor&lt;/a&gt; para una DSL que había construído encima de ChatScript. En resumen: me lo pasé bomba. Pero si has programado algún sistema parecido ya sabrás cómo acaba la cosa…&lt;/p&gt;

&lt;p&gt;Yo había estado leyendo mucho, sobre &lt;a href=&quot;https://github.com/ChatScript/ChatScript/tree/master/PAPERS&quot;&gt;Wilcox y ChatScript&lt;/a&gt;, el premio Loebner y chatbots en general. &lt;a href=&quot;/public/papers/ferrucci2012.pdf&quot;&gt;Sobre Watson, cómo lo desarrollaron y su arquitectura&lt;/a&gt;. Sobre &lt;a href=&quot;/public/papers/yedalog.pdf&quot;&gt;Yedalog&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Datalog&quot;&gt;Datalog&lt;/a&gt;, sobre &lt;a href=&quot;https://martinfowler.com/dsl.html&quot;&gt;DSLs&lt;/a&gt;, sobre modelos de lenguaje, ML, NLP… Había leído un poco a &lt;a href=&quot;https://colab.research.google.com/github/norvig/pytudes/blob/main/ipynb/How%20to%20Do%20Things%20with%20Words.ipynb&quot;&gt;Norvig&lt;/a&gt;, &lt;a href=&quot;http://norvig.com/chomsky.html&quot;&gt;lo suficiente como para saber que sólo con reglas no iba a conseguir mi objetivo, por muy rápido e ingenioso que fuera ChatScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;(Tangencialmente, tanto Wilcox como Norvig habían trabajado en LISP, y además estaba en pleno auge el furor por la programación funcional en JavaScript, así que también me interesé bastante en LISP y en Clojure, pero eso es otra historia, que contaré en otro momento ;))&lt;/p&gt;

&lt;p&gt;De leer todo esto había sacado muchas ideas y había añadido muchas heurísticas a mi chatbot. Había añadido cientos de tests end to end automáticos para saber que al añadir nueva funcionalidad, el chatbot no dejaba de responder bien a las acciones que ya conocía… Añadí un pequeño motor lógico que permitía “enseñarle cosas”, es decir guardar hechos y relaciones mediante lenguaje más o menos natural… Todo con la intención de construir un sistema lo bastante flexible como para poder seguir añadiéndole “servicios” o piezas que lo hicieran más inteligente, como en Watson.&lt;/p&gt;

&lt;p&gt;Desde el principio el chatbot podía recibir de input y responder en cualquier idioma gracias a la API de traducción de Google, que hacía la conversión y de algunas reglas para detectar, almacenar el idioma y hacer la conversión de la salida desde ese momento para ese usuario.&lt;/p&gt;

&lt;p&gt;Yo estaba bastante contento con mi pequeño sistema experto multirepo que era capaz de responder a un puñado de preguntas, hacer bromas y tener pequeñas conversaciones, siempre que preguntaras la pregunta adecuada…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pero tratar de programar un chatbot o un asistente genérico, que responda airosamente a texto libre, escribiendo reglas a mano, es una tarea imposible.&lt;/strong&gt; Por mucho que generalicen tus reglas, mucho entity detection, bases de datos con ciudades, nombres, animales y demás que tengas, por más que tokenices la frase y que elimines las palabras superfluas como los artículos, por más que uses regex en tus reglas, siempre llegará el usuario, intentará hablar con tu programa y tu programa fracasará estrepitosamente en entenderlo, si no a la primera, a la segunda frase.&lt;/p&gt;

&lt;p&gt;Era bastante frustrante tener miles de tests unitarios, cientos de tests automáticos de conversaciones e2e en varias categorías, desde hablar del usuario, dar el tiempo, la hora, preguntas de cálculos, bromas, ejecutar comandos, memorizar cosas, recordar cosas, poner contadores… y que nada más intentar probarlo alguien, fallara en entenderlo y respondiera con un “lo siento, no te entiendo” o algunas de las decenas de frases que tiene ChatScript para intentar salir del paso en ese caso.&lt;/p&gt;

&lt;p&gt;Pero entonces en la empresa me hicieron un regalo: Un compañero!! Había otro programador, esta vez alguien especializado en ML, que estaba intentando el mismo problema usando todo ese royo de Python y Spacy, con el mismo o menos éxito que yo, así que nos pusimos los dos a intentar aunar fuerzas.&lt;/p&gt;

&lt;p&gt;Yo ya tenía el servidor funcionando y además como había añadido todos esos módulos independientes y había ido desacoplando todo, podía incorporar otro servidor, en este caso de ML, que respondiera a todo aquello que a mi chatbot se le escapaba. Al principio fue solo eso, luego fuimos añadiendo pesos, y si el ML estaba muy seguro de la respuesta, respondía el ML, si no, el chatbot, si el chatbot no tenía respuesta, respondíamos algo genérico.&lt;/p&gt;

&lt;p&gt;Para poder encajar todo esto, ayudé un poco con el servidor de Python del sistema de ML, y esto me permitió acercarme un poco más a ese mundo. En el lado de Python usamos flask para el servidor y RASA para el chatbot. RASA tenía apenas unos meses y estaba muy verde (de hecho no existía o era poco más que una idea cuando yo empecé a investigar sobre el tema), usábamos spacy para tokenización y otras tareas clásicas de NLP pero por debajo de RASA lo customizamos un poco y el otro programador tenía tus propios modelos para detección de entidades y generación de lenguaje.&lt;/p&gt;

&lt;p&gt;Todo esto fue antes de GPT2, y tratábamos de seguir los últimos papers que iban saliendo sobre el tema. Yo me había familiarizado con los papers académicos porque sobre todo este tema apenas encontrabas información y cursos más asequibles en la web&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, y aunque pasaba de largo de las matemáticas, podía leer más o menos los papers que íbamos viendo que podían ser interesantes.&lt;/p&gt;

&lt;p&gt;Ni que decir tiene que nuestro chatbot seguía siendo bastante patata, pero tenia un montón de funcionalidades si sabías usarlo. Este era el problema siempre antes de GPT3.5, simplemente no existía nada que entendiera la pregunta y diera una respuesta coherente. Ahora mismo nos quejamos de que la IA se &lt;em&gt;“inventa”&lt;/em&gt; cosas, pero el salto es abismal, &lt;strong&gt;en 2019 el estado del arte era&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Tokenizar&lt;/strong&gt; y limpiar la entrada&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Detección de entidades&lt;/strong&gt; con diccionarios en el lado clásico o con un NER en ML.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Clasificación de la intención&lt;/strong&gt; de la frase:
    &lt;ul&gt;
      &lt;li&gt;En el lado clásico esto eran cientos o miles de reglas y regex para tratar de hacer matchear la frase con un patrón conocido.&lt;/li&gt;
      &lt;li&gt;En ML podías entrenar un clasificador con las intenciones que tuvieras y el clsaificador te daba una intención o varias con un margen de confianza.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Con la intención, si tienes algo con confianza alta, y tienes las entidades (variables como Paris, Juan o concierto) &lt;strong&gt;puedes intentar responder&lt;/strong&gt;. Si no, tienes un backup tipo &lt;a href=&quot;https://en.wikipedia.org/wiki/ELIZA&quot;&gt;ELISA&lt;/a&gt; que da respuestas genéricas, intenta ser gracioso o te pide disculpas por que no te ha entendido.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Responder en sí es muy complicado&lt;/strong&gt;, pongamos que el usuario te pregunta si está lloviendo en Paris. Paris es enorme, tu API del tiempo de pide un código postal o unas coordenadas, tienes que ser capaz de decidir cuáles darles, con una base de datos o otro servicio que te de coordenadas dada una ciudad… y Paris es fácil, pero ¿y si te dicen “Córdoba”? ¿La de España? ¿La de Argentína? ¿La de USA? ¿Desde dónde pregunta el usuario? tal vez eso pueda servir para saber lo que está pidiendo… ¿Y si te pide un dato genérico cómo la temperatura máxima registrada en el Sahara, o una conversión de unidades, o que le des un resumen de un libro o una persona?… es un agujero de conejo que nunca termina. Damos por supuesto un motón de funcionalidad que Google lleva 25 años construyendo con cientos de ingenieros y expertos y miles de millones de webs a las que enlazar.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A los pocos meses llegó &lt;strong&gt;GPT2&lt;/strong&gt; &lt;a href=&quot;/public/papers/gpt2.pdf&quot;&gt;el famoso paper de los unicornios&lt;/a&gt; y nos voló la cabeza, intentamos añadir algo con BERT que diera respuestas libres, se empezó a hablar del prompt engineering… Y entonces llegó la mudanza, mi cambio de trabajo, la pandemia… y desconecté durante 2 años de todo ese mundo bastante de golpe. En algún momento, &lt;del&gt;creo que poco antes de irme de ese trabajo&lt;/del&gt; poco después de irme de ese trabajo, llegó GPT3, yo ya estaba bastante desconectado del tema y tratando de estar a la altura del nuevo trabajo, pero aun así estuve comentándolo con mis antiguos compañeros, porque me pareció impresionante, pero aun así todo el tema del prompt engineering y cómo probar GPT3 me pareció demasiado poco determinista, yo estaba liado con otras cosas, así que no le dediqué mucho tiempo y acabé olvidándome de eso.&lt;/p&gt;

&lt;p&gt;Nunca había sido capaz de estudiar ML y no entendía cómo se entrenaban los modelos o cómo funcionaban. Además el proceso de entrenamiento siempre me ha parecido algo terriblemente aburrido y demasiado azaroso: tienes que esperar días para ver el resultado y lo más seguro es que lo tires a la basura, cambias algunos parámetros o revisas los datos de entrenamiento y vuelta a empezar… El ciclo del feedback es demasiado lento. Me gustaba trabajar con TDD en JavaScript, así que abandoné todo ese mundo pensando que aun no estaba maduro y no merecía la pena para mi.&lt;/p&gt;

&lt;p&gt;Imagina mi sorpresa cuando OpenAI anunció ChatGPT y empecé a ver de lo que era capaz. 🤯&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Estamos hablando de 2017-19, no existía huggingface o estaba muy verde, al igual que la web de Spacy y de encontrar algo en StackOverflow o en blogs especializados ni hablar, había mucha gente intentando hacer un chatbot, pero la mayoría eran cosas muy burdas de árboles de decisiones, y pulsa 1 para X, dos para Y, o como mucho algunas regexes añadidas a esos condicionales… &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Cómo ejecutar github pages en local con Docker</title>
   <link href="http://juanmirod.github.io/2023/05/17/github-pages-local.html"/>
   <updated>2023-05-17T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2023/05/17/github-pages-local</id>
   <content type="html">&lt;p&gt;Si usas github pages para tu blog o tu web pero no quieres instalar Ruby
y las demás dependencias en tu máquina o no sabes cómo, iterar sobre
cambios en el diseño o en el contenido se vuelve bastante tedioso: haces los cambios,
git commit, git push, espera a que se ejecute la acción que compila y publica la web…&lt;/p&gt;

&lt;p&gt;Así es muy difícil avanzar y mantener el flow. Yo hasta ahora estaba así porque
no quería instalar Ruby y jekyll y no quería dedicar mucho tiempo a la web a parte de
escribir.&lt;/p&gt;

&lt;p&gt;Pero esta semana, y gracias a que ChatGPT me ayuda mucho a mantener el foco y a resolver
problemas, he podido crear un fichero de docker y los ficheros de dependencias necesarios
para ejecutar el blog en local, y hacer cambios y verlos en tiempo real. Puedes ver la
configuración en el repo de esta página, pero lo copio también aquí para más comodidad.&lt;/p&gt;

&lt;h2 id=&quot;dependencias&quot;&gt;Dependencias&lt;/h2&gt;

&lt;p&gt;Lo primero es añadir el &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; con las dependencias que tiene github-pages, incluidos los plugins
que estés utilizando, en mi caso sólo uso dos plugins y el Gemfile queda así:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;source &apos;https://rubygems.org&apos;

require &apos;json&apos;
require &apos;open-uri&apos;
versions = JSON.parse(open(&apos;https://pages.github.com/versions.json&apos;).read)

gem &apos;github-pages&apos;, versions[&apos;github-pages&apos;]
gem &apos;jekyll-seo-tag&apos; 
gem &apos;jekyll-paginate&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este fichero va en la raíz del proyecto, igual que el dockerfile. También necesitarás docker instalado
en tu ordenador para poder ejecutar el dockefile.&lt;/p&gt;

&lt;h2 id=&quot;dockerfile&quot;&gt;Dockerfile&lt;/h2&gt;

&lt;p&gt;El dockerfile se encarga de instalar todas las dependencias en un contenedor y ejecutar el install, el build y el servidor de jekyll para que puedas ver la página en local sin conexión y trabajar mucho más
rápido. Este es el &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dockerfile&lt;/code&gt; que deberá estar en la raíz del proyecto:&lt;/p&gt;

&lt;div class=&quot;language-dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; jekyll/jekyll:3.8&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; /site&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; . .&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chmod &lt;/span&gt;a+w Gemfile.lock 

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;jekyll build

&lt;span class=&quot;k&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [&quot;jekyll&quot;, &quot;serve&quot;, &quot;--watch&quot;, &quot;--force_polling&quot;, &quot;--incremental&quot;, &quot;-H&quot;, &quot;0.0.0.0&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;cómo-usarlo&quot;&gt;Cómo usarlo&lt;/h2&gt;

&lt;p&gt;Para usar el dockerfile primero compilamos la imagen con el siguiente comando:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker build &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; myblog &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(La primera vez que ejecutes el build se creará un fichero &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile.lock&lt;/code&gt; que guarda la versión de las
dependencias de ruby instaladas, te recomiendo añadirlo a tu repo para tener las dependencias apuntando
a versiones fijas)&lt;/p&gt;

&lt;p&gt;Y ya podemos ejecutar el contenedor:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 4000:4000 &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:/site myblog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y podrás ver el blog en &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost:4000&lt;/code&gt; en watch mode, lo que quiere decir que cualquier cambio dispara
un re-build y si refrescas la página verás la nueva versión de la web con el cambio.&lt;/p&gt;

&lt;p&gt;A mi ha ayudado a poder cambiar el css de la web, espero que sea útil a alguien más y como siempre para
cualquier comentario o corrección de errores puedes abrir un issue en &lt;a href=&quot;https://github.com/juanmirod/juanmirod.github.io&quot;&gt;github&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Desarrollando con ChatGPT</title>
   <link href="http://juanmirod.github.io/2023/04/16/trabajando-con-chat-gpt.html"/>
   <updated>2023-04-16T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2023/04/16/-trabajando-con-chat-gpt</id>
   <content type="html">&lt;p&gt;Llevo un tiempo siguiendo la pista a los avances de la IA, IAs generativas, modelos de lenguaje, etc. pero ChatGPT me pareció un cambio de paradigma que tenía que atacar desde el principio. Fue una señal de que me estaba perdiendo algo importante y debía empezar a aprender más seriamente sobre el tema.&lt;/p&gt;

&lt;p&gt;Una de las cosas que hago es seguir leyendo y haciendo cursos sobre Python, ML, LLMs. Pero los cursos siempre me parecen demasiado dirigidos, para mi es importante también tener un proyecto libre que me permita experimentar y aprender a mi ritmo y ver el por qué y el cómo.&lt;/p&gt;

&lt;p&gt;Para eso empecé un &lt;a href=&quot;https://github.com/juanmirod/chatgpt_cli&quot;&gt;proyecto personal&lt;/a&gt; en el que la propuesta es crear mi propio asistente personal. Idealmente uno que sepa cosas sobre mi y tenga memoria sobre nuestras conversaciones anteriores y aún más idealmente que se ejecute en mi ordenador personal. Todavía estoy lejos de expectativas y puede que nunca llegue a conseguirlas pero es una forma de forzarme a aprender sobre el tema.&lt;/p&gt;

&lt;p&gt;El segundo punto importante de este proyecto es que &lt;strong&gt;estoy haciéndolo en python, que no es mi lenguaje principal, y que además estoy haciéndolo usando siempre que puedo ChatGPT antes que google o documentaciones externas.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Todo esto lo convierte en algo bastante meta, que es algo que me encanta, uso ChatGPT para desarrollar herramientas que usen ChatGPT y en última instancia reemplazarlo con mi propio ChatGPT…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por ahora la experiencia es genial. Desarrollo nuevas funcionalidades muy rápido, ChatGPT me desbloquea muchísimo y me mantiene mucho más en el flow&lt;/strong&gt; que tener que estar leyendo documentación o buscando en Google y en general la sensación de velocidad y de satisfacción es muy buena. También creo que esto es así porque estoy usando ChatGPT en el escenario ideal:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Un proyecto nuevo y pequeño.&lt;/li&gt;
  &lt;li&gt;Una app de línea de comandos, con lo que añadir funcionalidad es muy fácil, no necesitas frameworks ni componentes ni grandes arquitecturas.&lt;/li&gt;
  &lt;li&gt;En un lenguaje que no domino, con lo que ChatGPT es muy útil para solventar dudas.&lt;/li&gt;
  &lt;li&gt;El propio dominio es la especialidad de ChatGPT.&lt;/li&gt;
  &lt;li&gt;Python es un lenguaje especialmente adecuado para LLMs, porque no tiene tanta sintaxis y es dinámico. Propiedades que lo hacen ideal para humanos y para LLMs porque ahora mismo es lo más parecido a que teníamos a programar en lenguaje natural.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sin todos estos factores la utilidad ahora mismo de ChatGPT pierde puntos. De hecho en el trabajo lo uso mucho menos, simplemente es más difícil explicar lo que quiero que hacerlo yo. Pero por eso creo que todos acabaremos con nuestro propio asistente personal o de empresa que conozca los entresijos de nuestros proyectos y pueda ayudarnos con más contexto…&lt;/p&gt;

&lt;p&gt;Pero vayamos un poco al grano, voy a listar algunos ejemplos de cómo he usado ChatGPT en este proyecto y cuando pueda enlazaré a conversaciones concretas sobre ese tema que tuve con ChatGPT. Estas son algunas cosas que he hecho con ChatGPT para trabajar, y no sólo para explorar lo que sabe, aprender o tratar de jugar o entretenerme:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Readme:&lt;/strong&gt; La primera versión del Readme la escribió ChatGPT, yo la edité y he ido ampliándolo y mejorándolo desde entonces.&lt;a href=&quot;https://gist.github.com/juanmirod/fce0104af6714c7527fce54639706407&quot;&gt;Lee la conversación aquí&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Dockerfile:&lt;/strong&gt; Le pedí a ChatGPT un dockerfile porque la verdad es que no me sé la sintaxis que hay que seguir y al final siempre acabo copiando y pegando. De primeras me dió un dockerfile totalmente funcional y el comando para ejecutar el asistente desde el dockerfile. Luego lo edité un poco para quitar alguna cosa que no necesitaba y cambiar un poco el orden de los comandos para aprovechar mejor la cache de docker.&lt;a href=&quot;https://gist.github.com/juanmirod/7be1a16f017ea8798754870d1bcd7ffa&quot;&gt;Conversación&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;TTS:&lt;/strong&gt; El asistente tiene una opción de text-to-speech para que puedas escucha sus respuestas, aunque por defecto lo tengo desactivado (es más rádpido leer y el código no tiene sentido escucharlo) La primera versión de nuevo fue suya, luego estuve probando varias voces y librerías, al final me quedé con una que no era la que me había sugerido ChatGPT.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Subir conversación a un gist.&lt;/strong&gt; El fichero upload también se lo pedí a ChatGPT, luego yo metí el código en una función para usarlo desde la app en lugar de como un script.&lt;a href=&quot;https://gist.github.com/juanmirod/8b6044b0071bdcc5cb0bbcf933b7a576&quot;&gt;Conversación&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Recuperar una conversación&lt;/strong&gt; desde el fichero markdown. Esto aún no lo tengo integrado, pero ya he peloteado con ChatGPT y tengo el código inicial que debería hacerlo posible. &lt;a href=&quot;https://gist.github.com/juanmirod/4f0e8687b4620831afb1446aed027b0c&quot;&gt;Conversación&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Hablando de embeddings y cómo usarlos&lt;/strong&gt; Para poder guardar información de texto y hacer búsquedas semánticas. &lt;a href=&quot;https://gist.github.com/juanmirod/6429d962b6ffb71f2bc9a3cdb27cbd71&quot;&gt;Conversación&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Refactors.&lt;/strong&gt; He hecho varios refactors donde le he dado una función grande y le he pedido que me parta en funciones más pequeñas.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Tests.&lt;/strong&gt; Los primeros tests de la clase ChatGPT los hizo ChatGPT, los del módulo de actions los he hecho con ayuda de copilot.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En general ChatGPT me ha ayudado durante todo el proceso. Tanto a esbozar soluciones, consultar cómo funcionan librerías, escribir tests… el patrón es parecido siempre, y por eos creo que especialmente útil si no dominas el lenguaje, porque si lo dominas vas a tardar lo mismo o menos en escribirlo tú. Pero si no conoces las librerías y módulos disponibles, pedirle a ChatGPT cómo lo haría ahorra mucho tiempo de prueba y error e investigación y leer documentación. Además para mi este proceso suele ser un agujero de conejo: me pongo a buscar una librería para hacer X y hay 100, y ahora tengo que ver cuales son más populares y por qué y quiero ver un poco cómo funcionan… y cuando me he dado cuenta han pasado 2 horas y no he hecho nada. Con ChatGPT todo ese proceso es mucho más inmediato y fluido, incluso aunque acabe usando otra librería o editando fuertemente o descartando su primera solución. Me mantiene más en el flow y más centrado en el problema que todas esas webs llenas de anuncios y popups de cookies, y videos y demás distracciones.&lt;/p&gt;

&lt;p&gt;Estoy seguro de que sólo estoy rascando la superficie aquí. los LLMs parecen tener muchísimo potencial a varios niveles, y poco a poco iremos integrándolos en IDEs e interfaces de usuarios, pero incluso en esta forma rudimentaria y sin saber muy bien lo que hago creo que gano mucha productividad y el proceso de desarrollo es mucho menos frustrante.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>¿Por qué es tan importante ChatGPT?</title>
   <link href="http://juanmirod.github.io/2023/03/26/chat-gpt.html"/>
   <updated>2023-03-26T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2023/03/26/chat-gpt</id>
   <content type="html">&lt;h2 id=&quot;qué-es-chatgpt&quot;&gt;¿Qué es ChatGPT?&lt;/h2&gt;

&lt;p&gt;Tal vez haz llegado aquí por una búsqueda orgánica o desde un futuro donde ChatGPT
ya no es la noticia del momento, así que por completitud lo repetiré una vez más: ChatGPT es un modelo de lenguaje entrenado para interactuar con personas en conversaciones de chat. Hace algunos años que los expertos en el campo han estado probando y usando estos LLMs (del inglés Large Language Model) para diferentes tareas como detección de intención, detección de sentimientos, clasificación de comentarios, predicción de textos en herramientas como el teclado del teléfono móvil o el email, generación de texto, etc.&lt;/p&gt;

&lt;p&gt;Pero esta es la primera vez que el gran público puede interactuar con uno de forma fácil y abierta, y gracias al entrenamiento especial que ha tenido, es capaz de mantener conversaciones, entender y responder preguntas, corregir errores en sus respuestas anteriores… y ahora conforme la gente empieza a aprender a darle instrucciones también usar APIs de terceros y lenguajes de programación como Wolfram Alpha para responder a las preguntas.&lt;/p&gt;

&lt;h2 id=&quot;por-qué-es-esto-tan-importante&quot;&gt;¿Por qué es esto tan importante?&lt;/h2&gt;

&lt;p&gt;ChatGPT es un salto cualitativo respecto a lo que teníamos hasta ahora en cuanto a potencia y usabilidad.
Especialmente el modelo GPT4, que acaba de salir, tiene una ventana de contexto mucho más grande que sus predecesores y ha sido capaz de superar una gran cantidad de exámenes del nivel de bachillerato o de pruebas de evaluación para puestos de trabajo. Por estos motivos hay quien habla de que ChatGPT podría ser un primer paso hacia una AGI (del inglés Artificial General Intelligence) o inteligencia artificial general.&lt;/p&gt;

&lt;p&gt;Para mi esto es demasiado, ChatGPT es impresionante, pero aún dista mucho de poder hacer muchas tareas de
forma independiente y no tiene ningún tipo de persistencia ni de agencia, con lo que ahora mismo es sólo
un sistema que responde bastante bien una gran batería de preguntas.&lt;/p&gt;

&lt;p&gt;Pero sus aplicaciones como asistente virtual y para educación son enormes, y es ahí donde estamos viendo a muchas startups y aficionados tratar de sacarle partido. Desde Khan Academy, Duolingo, Quizlet, hasta Microsoft, todos anuncian nuevas funcionalidades que aprovechan esta tecnología.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hacía años que no veíamos una reacción así por parte de las empresas tecnológicas.&lt;/strong&gt; Incluso durante el confinamiento, cuando era evidente que había una oportunidad de mercado en aplicaciones de videoconferencia, la mayoría fueron demasiado lentas en reaccionar. Pero apenas días o semanas tras el anuncio de OpenAI de ChatGPT ya había integraciones de todo tipo.&lt;/p&gt;

&lt;p&gt;Esto se debe a dos cosas:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;En OpenAI hicieron muy bien su trabajo&lt;/strong&gt; y ChatGPT pudo soportar un crecimiento nunca visto y a millones de usuarios desde el segundo día. Además la API también está disponible desde el día 1 y es extremadamente simple de usar, apenas 1 endpoint y 2 o 3 parámetros son suficiente para interactuar con ChatGPT de forma programática.&lt;/li&gt;
  &lt;li&gt;La gente ve el potencial nada más probarlo. Puedes notar que no había nada parecido a esto hasta ahora. Llevamos años teniendo asistentes en los móviles, en la televisión, en los relojes, en altavoces de salón… y no los usábamos más que para darles órdenes simples y concretas. En el momento en el que pruebas 5 minutos ChatGPT te das cuenta de que es otra cosa, puede mantener el hilo de una conversación, responde con sentido a casi cualquier cosa que le preguntas, le puedes pedir una canción, una poesía un trozo de código o un cuento infantil y puedes ver que la respuesta no ha sido programada ni es una elección aleatoria de una base de datos, es algo dentro del contexto de la conversación y a lo que le puedes pedir que haga cambios o mejoras.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esto ha enganchado a muchos y sorprendido a la mayoría. Pero para mi sigue sin ser lo más importante. &lt;strong&gt;Lo más importante es que te entiende.&lt;/strong&gt; Voy a dejar de lado el si realmente piensa o no o si razona o no o si miente o se inventa cosas, porque para mi todo eso es más o menos irrelevante. &lt;strong&gt;El verdadero cambio de paradigma no es usar ChatGPT como una IA que todo lo sabe, es usarla como interface.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;chatgpt-como-interface&quot;&gt;ChatGPT como interface&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Por primera vez tenemos un sistema digital que entiende el lenguaje natural.&lt;/strong&gt; Dentro de unos meses esto parecerá normal, pero hasta ahora todo lo que teníamos eran bots que entendían órdenes pre-programadas o directamente números (pulse 1 para facturas, 2 para darse de baja…) o asistentes virtuales que el 50% de las veces no te entendían y del otro 50 la mitad de las veces no podían hacer lo que les pedías.&lt;/p&gt;

&lt;p&gt;Pero ahora, de repente, tenemos un sistema que entiende lenguaje natural, (¡En un montón de idiomas!) y puede realizar acciones o responder de forma semi inteligente.&lt;/p&gt;

&lt;p&gt;Creo que esto es realmente lo que atrapa a la mayoría, aunque no sepan muy bien qué hacer con él o qué preguntarle, podemos notar que aquí hay potencial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cualquier persona sin conocimientos de programación puede sacar partido inmediato de esto.&lt;/strong&gt; De hecho yo por ahora le he dado tres usos principales: usarlo en lugar o como complemento a Google para buscar cosas, usarlo como tutor para aprender (en lugar de leer un libro o una documentación le vas preguntando cosas y te las va contestando, aprendizaje totalmente personalizado) y sólo como curiosidad le he pedido que me genere funciones o tests (normalmente tardo menos en escribirlo yo mismo que en explicarle lo que quiero, pero sí que es verdad que a veces ahorra boilerplate).&lt;/p&gt;

&lt;h2 id=&quot;qué-usos-podrán-tener-los-llms-en-un-futuro-próximo&quot;&gt;¿Qué usos podrán tener los LLMs en un futuro próximo?&lt;/h2&gt;

&lt;p&gt;A parte de la conversión directa a chatbot+contexto del ámbito que sea, creo que los LLMs tienen un potencial enorme como interface de aplicaciones y como generadores de contenido para videojuegos.&lt;/p&gt;

&lt;p&gt;En una aplicación, la demostración de Microsoft con Office es una muestra de hacia donde podría ir la industria. Asistentes inteligentes en las aplicaciones de forma que ya no hace falta aprenderse todas las opciones de la UI, le dices al modelo lo que quieres y él se encarga de ejecutar.&lt;/p&gt;

&lt;p&gt;Otra aplicación en la misma línea pero enfocada al desarrollo sería permitir a los usuarios crear código y automatizaciones mediante lenguaje natural. Un poco lo que ya vemos con el plugin de Zappier para ChatGPT pero a nivel de herramientas de desarrollo. Imagina un IDE o un lenguaje que incluyen un LLM que corre en local como parte
propia del lenguaje… En &lt;a href=&quot;https://technium.transistor.fm/episodes/llms-eat-software-development&quot;&gt;este podcast de The Technium&lt;/a&gt; exploran esa idea desde varios puntos de vista y cómo podría también permitir a los usuarios de una app crear plugins o funcionalidades o personalizaciones en lenguaje natural.&lt;/p&gt;

&lt;p&gt;La otra aplicación muy comentada es como generador de contenidos. Ya existen start-ups como &lt;a href=&quot;https://www.jasper.ai/&quot;&gt;Jasper&lt;/a&gt; o &lt;a href=&quot;https://www.copy.ai/&quot;&gt;copy.io&lt;/a&gt; que utilizan a GPT3 para generar copys, blogposts, emails, redacciones, resúmenes…&lt;/p&gt;

&lt;p&gt;Por último, aún no tienen la velocidad necesaria, pero cuando whisper y chatGPT sean más rápidos, podremos hablarle a los NPJ de un juego y que nos respondan o ejecuten nuestras órdenes sin necesidad de nada más, se acabaron las conversaciones enlatadas y la selección de diálogos fijos. Los diseñadores podrían darle un papel y un guión a ChatGPT y a partir de ahí el jugador podrá preguntar lo que quiera y tener una respuesta coherente. Se me ocurre que podría revolucionar el campo de las aventuras gráficas, donde ya telltale avanzó mucho gracias al lenguaje chatscript de Bruce Wilcox, pero esto es otro nivel totalmente.&lt;/p&gt;

&lt;h2 id=&quot;van-a-quitarme-el-trabajo&quot;&gt;¿Van a quitarme el trabajo?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Esta tecnología va a suponer una revolución en el software comparable al de internet, seguramente mayor.&lt;/strong&gt; Muchos trabajos desaparecerán, otros cambiarán. ChatGPT no tiene capacidad para sustituir a nadie por si sólo, esa es una premisa absurda a la que mucha gente se agarra para decir que la IA no va a sustituir a ningún profesional, pero me parece un señuelo para desestimar un tema de vital importancia.&lt;/p&gt;

&lt;p&gt;Las mejoras de productividad, las nuevas automatizaciones y los cambios en cómo interactuamos con muchas herramientas por su puesto que van a hacer a muchos trabajadores irrelevantes. No directamente en el sentido de quito a fulanito para poner a chatGPT a hacer su trabajo, pero está claro que así será.&lt;/p&gt;

&lt;p&gt;El software hace eso todo el rato, automatizamos procesos, trabajos, tareas… que hace que no haya que contratar a tanta gente para una tarea concreta. Si no no sería rentable, eso es lo que hacemos. &lt;strong&gt;Los LLMs son un multiplicador de esa capacidad.&lt;/strong&gt; Ahora mucha más gente va a poder crear software y automatizaciones, va a poder generar contenido sin un experto, o con muchos menos expertos, va a poder gestionar sus redes sociales o la atención al cliente de forma mucho más fácil y eficiente. Y todo eso va a tener un impacto en el mercado laboral de aquí a unos meses.&lt;/p&gt;

&lt;h2 id=&quot;y-qué-puedo-hacer&quot;&gt;¿Y qué puedo hacer?&lt;/h2&gt;

&lt;p&gt;Para mi la mejor estrategia es aprender a usar esta tecnología a tu favor para, en lugar de quedarte obsoleto, ser tú quien tome ventaja de ella. Sé que es la misma carrera hacia adelante de siempre, este correr cada vez más, la rueda de hamster del capitalismo… Pero por ahora no tengo una respuesta mejor. Los modelos como ChatGPT no van a ir a ningún lado, lo más probable es que se hagan totalmente ubicuos y cada vez más capaces, sólo nos queda adaptarnos y tratar de sacarle partido.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Domain Driven Design</title>
   <link href="http://juanmirod.github.io/2021/04/26/domain-driven-design.html"/>
   <updated>2021-04-26T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2021/04/26/domain-driven-design</id>
   <content type="html">&lt;p&gt;El Domain Driven Design (DDD) es una metodología de diseño de software que pone el foco en el dominio del problema que estamos tratando de resolver. La idea es que el código debe reflejar lo mejor posible el dominio del problema, usando su lenguaje y sus conceptos.&lt;/p&gt;

&lt;p&gt;// …existing code…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Chuleta de comandos útiles de Linux</title>
   <link href="http://juanmirod.github.io/2020/03/22/chuleta-linux.html"/>
   <updated>2020-03-22T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2020/03/22/chuleta-linux</id>
   <content type="html">&lt;p&gt;Algunos comandos que suelo utilizar con cierta frecuencia pero algunos no con la suficiente como para recordarlos. Se aceptan sugerencias de comandos o alias para incluir a la lista. No soy administrador de sistemas ni experto en Linux, solo usuario habitual.&lt;/p&gt;

&lt;h2 id=&quot;conexiones-ssh&quot;&gt;Conexiones ssh&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh-keygen&lt;/code&gt; Crear una clave ssh&lt;/li&gt;
  &lt;li&gt;Copiar la clave ssh al servidor a mano:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cat ~/.ssh/id_rsa.pub
** copiar la clave en el portapapeles **
** hacer login en el servidor **
echo pegar_la_clave_aquí &amp;gt;&amp;gt; ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh user@host&lt;/code&gt; Conectar al servidor&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh user@host &quot;comando&quot;&lt;/code&gt; Enviar comandos al servidor&lt;/li&gt;
  &lt;li&gt;Para desabilitar el login con clave en el servidor, una vez logado con ssh:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo nano /etc/ssh/sshd_config

...
PasswordAuthentication no
...

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;manejo-de-ficheros&quot;&gt;Manejo de ficheros&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mkdir nombre_de_carpeta&lt;/code&gt; Crea una nueva carpeta&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;touch nombre_de_fichero&lt;/code&gt; Crea un fichero vacío&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rm nombre_de_fichero&lt;/code&gt; Borra un fichero&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rm -r nombre_de_carpeta&lt;/code&gt; Borra una carpeta&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mv nombre_fichero nuevo_nombre&lt;/code&gt; Renombra/mueve un archivo&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cp nombre_fichero nuevo_fichero&lt;/code&gt; Copia un archivo&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt; - muestra un listado con los ficheros de la carpeta actual&lt;/li&gt;
  &lt;li&gt;Encontrar un fichero dentro de un arbol de directorios, excluyendo (podando) algunos:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; find . -not \( -path &quot;*/node_modules&quot; -prune  \) -name &quot;filename*&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;ayuda-e-información&quot;&gt;Ayuda e información&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Para ver ficheros en la linea de comandos podemos usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;more&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;less&lt;/code&gt;, este último es el que usan las man pages.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;info coreutils&lt;/code&gt; Muestra un manual con hipervínculos sobre los principales programas GNU de Linux&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;whatis&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type&lt;/code&gt; sirven para saber que hace un comando y de que tipo es para más info se puede usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;info&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man&lt;/code&gt; o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--help&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alias&lt;/code&gt; para crear comandos a partir de otros.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd -&lt;/code&gt; para volver al directorio anterior&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;imprimir-desde-la-línea-de-comandos-pdf-ps-jpg&quot;&gt;Imprimir desde la línea de comandos (pdf, ps, jpg)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lpq&lt;/code&gt; - muestra la cola de impresión&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lp nombredefichero.pdf&lt;/code&gt; - imprime en la impresora por defecto&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lp -o sides=two-sided-long-edge Notes.pdf&lt;/code&gt; - imprimir por las dos caras&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lp -o landscape penguin.jpg&lt;/code&gt; - Imprimir apaisado&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;history | lp -o portrait -o fit-to-page -&lt;/code&gt; Imprime lo que recibe desde standard-input&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;convertir-a-pdf&quot;&gt;Convertir a pdf&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Convertir un rtf o doc/docx a pdf con libreoffice desde cli:
  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libreoffice --headless --invisible --norestore --convert-to pdf fichero.rtf&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Convertir markdown a pdf (con node y headless chrome):
  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npx markdown-pdf README.md readme.pdf&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Latex a pdf:
  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pdflatex ...&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;utilidades-varias&quot;&gt;Utilidades varias&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notify-send&lt;/code&gt; crea una notificación en el escritorio. Ej. crear una alarma para dentro de 10 segundos: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sleep 10; notify-send &quot;Hora e descansar!&quot; &quot;Se ha terminado el Pomodoro&quot;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Los comodines siempre se expanden en orden: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat *.txt &amp;gt; out.txt&lt;/code&gt; concatenará los ficheros &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.txt&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.txt&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;3.txt&lt;/code&gt; en ese orden. También se pueden usar expansiones con llaves: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{1..9}&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{a..z}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script filename&lt;/code&gt; guarda una sesion de comandos en un fichero, genial para crear scripts a partir de tareas manuales que solemos repetir.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;df -h&lt;/code&gt; te dice el espacio libre en los discos duros&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;free -h&lt;/code&gt; para espacio libre en la RAM&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;du -sh foldername&lt;/code&gt; dice el espacio ocupado por el directorio, si haces: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;du -sh *&lt;/code&gt; te dice el espacio que ocupan todos los subdirectorios del directorio actual&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep -iR &apos;palabra&apos; .&lt;/code&gt; Muestra todas las líneas que contienen &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;palabra&lt;/code&gt; en todos los ficheros del directorio actual y sus subdirectorios&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl+r&lt;/code&gt; búsqueda incremental en el historial, presionar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl+r&lt;/code&gt; otra vez para buscar más ocurrencias, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ctrl+j&lt;/code&gt; copia el comando y devuelve el control, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ENTER&lt;/code&gt; lo ejecuta.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;history&lt;/code&gt; te muestra el historial de comandos, con lo que puedes buscar en el historial haciendo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;history | grep &apos;comando&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wc -l&lt;/code&gt; muestra el número de líneas del stream se le pase, por ejemplo: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat file.txt | wc -l&lt;/code&gt; nos dá el número de líneas de un fichero y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grep -iR &apos;palabra&apos; . | wc -l&lt;/code&gt; nos daría el número de líneas en las que aparece la palabra &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;palabra&lt;/code&gt; en todos los ficheros del directorio y sus hijos.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;convert *.png out.pdf&lt;/code&gt; crea un pdf con una imagen por página.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=out.pdf first.pdf second.pdf&lt;/code&gt; Concatena varios pdfs en uno con ghostscript&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fc-cache -f -v&lt;/code&gt; Refrescar las fuentes de sistema una vez has copiado los ficheros de fuentes que quieres añadir a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.fonts/&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Para modificar el nombre/convertir una serie de ficheros: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for i in *.pdf; do mv &quot;$i&quot; CS749__&quot;$i&quot;; done&lt;/code&gt;. Por ejemplo, si tenemos una carpeta con un montón de documentos de word que tenemos que imprimir, en lugar de abrirlos uno por uno y darle a imprimir, podemos hacer:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.doc&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do &lt;/span&gt;libreoffice &lt;span class=&quot;nt&quot;&gt;--headless&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--invisible&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--norestore&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--convert-to&lt;/span&gt; pdf &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;lp &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; es un comando que permite tener varias sesiones del terminal abiertas en paneles o en segundo plano, muy útil para no tener que depender de las pestañas y poder ver varios terminales a la vez, es fácil de usar y aumenta las posibilidades del terminal.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;alias&quot;&gt;Alias&lt;/h2&gt;

&lt;p&gt;Algunos son para comandos de arriba:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alias please=&apos;sudo $(fc -ln -1)&apos;&lt;/code&gt; - Ejecuta el comando anterior con ‘sudo’&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alias alert=&apos;notify-send --urgency=low -i &quot;$([ $? = 0 ] &amp;amp;&amp;amp; echo terminal || echo error)&quot; &quot;$(history|tail -n1|sed -e &apos;\&apos;&apos;s/^\s*[0-9]\+\s*//;s/[;&amp;amp;|]\s*alert$//&apos;\&apos;&apos;)&quot;&apos;&lt;/code&gt; - crea una notificación de escritorio, útil para lanzar una notificación cuando termina otro comando: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm build &amp;amp;&amp;amp; alert &apos;Terminó el build&apos;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alias cd..=&apos;cd ..&apos;&lt;/code&gt; Este me ahorra mucha frustración :)&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Manipulación del DOM en JavaScript</title>
   <link href="http://juanmirod.github.io/2019/06/24/chuleta-dom.html"/>
   <updated>2019-06-24T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2019/06/24/chuleta-dom</id>
   <content type="html">&lt;p&gt;Este documento es una pequeña referencia o chuleta de las funciones principales que podemos usar para manipular el DOM desde JavaScript, sin usar frameworks ni librerías externas.&lt;/p&gt;

&lt;p&gt;Para una introducción más completa en forma de tutorial puedes ir a &lt;a href=&quot;https://developer.mozilla.org/es/docs/Referencia_DOM_de_Gecko/Introducci%C3%B3n&quot;&gt;MDN&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;qué-es-el-dom&quot;&gt;¿Qué es el DOM?&lt;/h2&gt;

&lt;p&gt;El DOM da una representación del documento como un grupo de nodos y objetos estructurados que tienen propiedades y métodos. En resumen, es la representación de la página web en la memoria del navegador, a la que podemos acceder a través de JavaScript. El DOM es un árbol donde cada nodo es un objeto con todas sus propiedades y métodos que nos permiten modificarlo.
Estas son algunas funciones que nos permiten acceder y modificar los elmentos del DOM:&lt;/p&gt;

&lt;h2 id=&quot;acceso-a-elementos-del-dom&quot;&gt;Acceso a elementos del DOM&lt;/h2&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Obtiene un elemento por id&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;someid&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Obtinee una lista con los elementos que tienen esa clase&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByClassName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;someclass&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Obtiene una HTMLCollection con los todos los elementos &apos;li&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;LI&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Devuelve el primer elemento del documento que cumpla la selección (la notación es como en CSS)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;.someclass&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Devuelve una lista de elementos que cumplen con la selección (notación como en CSS)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;div.note, div.alert&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;acceder-a-hijospadres-de-un-elemento&quot;&gt;Acceder a hijos/padres de un elemento&lt;/h3&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Obtener los hijos de un elemento&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;someid&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hijos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;childNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Su nodo padre&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;padre&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;elem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;crear-nuevos-elementos-en-el-dom&quot;&gt;Crear nuevos elementos en el DOM&lt;/h3&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Para crear elementos llamamos a createElement con el nombre del elemento&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nuevoH1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;nuevoParrafo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Crear nodos de texto para un elemento&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textoH1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createTextNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hola mundo!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textoParrafo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createTextNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;lorem ipsum...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Añadir el texto a los elementos&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;nuevoH1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textoH1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;nuevoParrafo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textoParrafo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// también podemos asignar directamente el valor a la propiedad innerHTML&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;nuevoH1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textoH1&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;nuevoParrafo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;textoParrafo&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// los elementos estarían listos para añadirlos al DOM, ahora mismo solo existen en memoria, pero no serán visibles hasta que no los añadamos a un elemento del DOM&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;añadir-elementos-al-dom&quot;&gt;Añadir elementos al DOM&lt;/h3&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// seleccionamos un elemento&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Añadir elementos hijos a un elemento&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nuevoH1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nuevoParrafo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// También podemos añadir elementos ANTES del elemento seleccionado&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Tomamos el padre&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;padre&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Insertamos el h1 antes de la cabecera&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;padre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;nuevoH1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;También podemos añadir directamente un trozo de HTML antes o después de un elemento del DOM, supongamos que tenemos estos elementos en la página:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;box1&apos;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;aquí algo de texto&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;box2&apos;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;otro parrafo bla bla bla&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Podemos hacer:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;box2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;box2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;box2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertAdjacentHTML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;beforebegin&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;div&amp;gt;&amp;lt;p&amp;gt;un parrafo nuevo.&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// beforebegin - El nuevo HTML es insertado justo antes del elemento, a la misma altura (hermano).&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// afterbegin - El nuevo HTML se inserta dentro del elemento, antes del primer hijo.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// beforeend - El nuevo HTML se inserta dentro del elemento, después del último hijo.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// afterend - El nuevo HTML es insertado justo después del elemento, a la misma altura (hermano).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;añadireliminarmodificar-clases&quot;&gt;Añadir/eliminar/modificar Clases&lt;/h3&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Tomamos un elemento&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// elimina una clase del elemento&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;classList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Añade una clase si no existe&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;classList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;otra&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// añade o elimina varias clases a la vez&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;classList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;classList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Si la clase existe la elimina, si no existe, la crea&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;classList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toggle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;visible&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Devuelve true si el elemento contiene esa clase&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;cabecera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;classList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>Refactorizando switch y if-else encadenados</title>
   <link href="http://juanmirod.github.io/2018/10/26/refactor-if-switch.html"/>
   <updated>2018-10-26T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2018/10/26/refactor-if-switch</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/public/img/diomari-madulara-110583-unsplash.jpg&quot; alt=&quot;Photo of a row of switches&quot; /&gt;
&lt;small&gt;(Photo by Diomari Madulara on Unsplash)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Una de las construcciones sintácticas más discutidas desde la sentencia &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GOTO&lt;/code&gt; es &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt;. A menudo es criticada y es que la sentencia switch tiene el problema de que es una fuente de acoplamiento. Seguro que si lleva un tiempo programando te ha ocurrido algo parecido a esto:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;En la base de código en la que trabajas hay una clase/módulo/función especialmente grande. En principio no parece que haya nada raro, esta función controla una parte importante del flujo del programa, puede que sea una máquina de estados, un clasificador que selecciona la acción adecuada en función del evento o acción recibidos… Y esa selección la hace mediante un switch. Ok, esta es la función para la que se ideó: le das una variable y ejecuta el case que coincide con el valor de esa variable. El problema del switch es que no te permite separar los casos y testarlos o modificarlos. Tienen que estar todos juntos y de forma secuencial en el código. Además tiene la peculiaridad de que, si quieres, puedes no incluir un break y dejar que se ejecuten dos casos seguidos y si esto no fuera poco, los programadores tenemos la costumbre de añadir código allí donde está el problema, con lo que esos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;case&lt;/code&gt;s han ido creciendo con el tiempo y ahora para cualquier cosa que hace ese programa, tenemos que revisar todo el enorme switch manualmente. La pesadilla de cualquier desarrollador.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El acoplamiento se produce por la propia construcción, porque no te obliga a separar los diferentes casos y a mantener límites en tu código, Introducir límites y recudir el acoplamiento son dos labores importantes del desarrollador si no quieres verte hasta las rodillas en un lodazal de código espagueti.&lt;/p&gt;

&lt;p&gt;Vamos a ver cómo podemos refactorizar esas sentencias &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; para hacerlas más fácil de leer o para hacerlas desaparecer por completo. Voy a usar un ejemplo de switch muy sencillo para que el resto del programa no sea una distracción. Podría hacer el mismo ejercicio usando Redux y varios reducers, estos cambios se pueden aplicar igualmente y en la documentación de Redux hay muy buenos ejemplos de como eliminar los switchs de los reducers. Pero yo prefiero utilizar el ejemplo más simple posible, para poder centrarme en la refactorización del &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; y no en lo que hace.&lt;/p&gt;

&lt;p&gt;Este es nuestro código inicial, supongamos que tenemos una calculadora, y la función que decide que operación utilizar en función a la acción que le pasamos:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// esta es la acción que queremos ejecutar&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;multiply24&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// esta es nuestra función que controla que hacer según la acción que le pasemos&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;execAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; 
      &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; 
      &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;execAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;multiply24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ok, sencillo, fácil de entender. No creo que nadie tuviera un problema con este código.&lt;/p&gt;

&lt;p&gt;El problema viene luego, cuando vamos añadiendo operaciones a nuestra calculadora, añadimos cosas como la raiz cuadrada y de repente tenemos que tratar a parte los números negativos o en la división tenemos que tener cuidado con el cero… &lt;strong&gt;Vamos añadiendo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;case&lt;/code&gt;s y vamos añadiendo lógica dentro de cada uno de esos cases. La función va creciendo y se va convirtiendo en ese &lt;em&gt;“God object”&lt;/em&gt; que controla todo el programa.&lt;/strong&gt; ¿Por qué ocurre esto? pues porque la sentencia &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; tiene una sintaxis concreta que no nos permite partirla y separarla, no podemos modularizarla, tenemos que escribirla como un único bloque sintácticamente válido, y eso nos oblida a poner todo ahí.&lt;/p&gt;

&lt;p&gt;Una forma de aliviar este problema es meter el cuerpo de cada &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;case&lt;/code&gt; en una función, así al menos hemos separado la lógica de ese caso a una función a parte que podemos testear por separado. De camino vamos a eliminar los breaks y la variable de resultado, que no hacen más que obligarnos a recorrer mentalmente el switch:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;multiply&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;execAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; 
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; 
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Así, sacamos toda la lógica perteneciente a las acciones fuera del switch. El switch es solo una forma de seleccionar la acción correcta, lo que lo simplifica mucho. Además con los return vemos claramente que en cada acción termina la función y no sentimos la necesidad de revisar la función siguiente o de ver si hay más código después del switch.&lt;/p&gt;

&lt;p&gt;Pero aún estamos usando la sintaxis del &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt;, la cual es bastante poco DRY y además no permite al compilador ayudarnos si cometemos algún error. ¿Como podríamos eliminar esta construcción manteniendo la funcionalidad? Vamos a usar un objeto donde la clave será el valor del &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;case&lt;/code&gt; y el valor de esa clave será la función que queremos ejecutar para ese &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;case&lt;/code&gt;. Para ejecutarlo comprobamos si la clave que queremos ejecutar existe y si es así, ejecutamos la función correspondiente, si no, ejecutamos el default:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;execAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; 
    &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Simplificándolo un poco más gracias a ES6:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;multiply&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;zero&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;execAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;zero&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; 
    &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;PUFF&lt;/strong&gt; ¡¡Desapareció el Switch!!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Todo lo que tenemos ahora es una serie de funciones y una lógica de selección que solo es necesario leer la primera vez. No tenemos que que recorrer todas las funciones cada vez y podemos testear todo por separado. La función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execAction&lt;/code&gt; parece un poco más exotérica, si especialmente no te gusta el operador ternario puedes cambiarlo por un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt;. Pero la ventaja es que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execAction&lt;/code&gt; solo la leerás las dos primeras veces. Luego ya sabrás que tu código son las funciones de arriba y que cada nombre corresponde a una acción y que no pueden concatenarse ni hay nada más que se ejecute antes o después, puedes pensar solo en la función de esa acción, y eso simplifica mucho el modelo mental.&lt;/p&gt;

&lt;p&gt;Si queremos olvidarnos aún más de la lógica de la selección, o vamos a usar este patrón varias veces porque nuestro programa tiene muchos reducers o muchas máquinas de estado, podemos crear una clase que encapsule la selección. Esto es algo parecido a lo que hace express para el enrutamiento, solo que en este caso en lugar de usar patrones más complejos, usaremos una cadena para la selección de la acción:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Matcher&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;nx&quot;&gt;addMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;nx&quot;&gt;execAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; 
      &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
      &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Matcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;multiply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;execAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;multiply24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 8&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hemos creado una forma de reutilizar nuestra lógica y reducir al mínimo la síntaxis, usamos solo llamadas a funciones para crear los casos y ejecutar la selección y tanto la clase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Matcher&lt;/code&gt; como cada actión, se puede testear y modificar por separado. Misión cumplida. Pero esta no es la única construcción de este estilo que podemos tener, hay otra estructura de código usada comúnmente que puede tener el mismo problema. ¿Qué hacemos si lo que tenemos es un montón de if-else-if encadenados? (Este artículo está en construcción, vuelve en unos días para ver como sigue)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Listado de papers interesantes</title>
   <link href="http://juanmirod.github.io/2018/08/22/lista-de-papers.html"/>
   <updated>2018-08-22T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2018/08/22/lista-de-papers</id>
   <content type="html">&lt;p&gt;Había pensado escribir sobre estos papers poco a poco, pero la lista crece y solo he escrito sobre uno de ellos, así que he decidido poner la lista en el blog para al menos tener un registro de los papers que más me han marcado y a los que quiero poder volver en algún momento. Si alguien quiere comentar alguno estaré encantado de hacerlo por twitter o github. Crea un issue y yo responderé en cuanto pueda y añadiré aquí el enlace a modo de hilo de comentarios.&lt;/p&gt;

&lt;p&gt;El listado no tiene ningún orden particular, todos me parecen grandes ideas, unos son largos otros apenas dos páginas. Unos muy técnicos, otros más filosóficos…&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Should computers learn like humans?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://ai.google/research/pubs/pub43462&quot;&gt;Yedalog: exploring knowledge at scale&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Meta-Interpretive Learning from noisy images&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.google.com/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=2&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwjrx7fugYrcAhUPblAKHXX8A2UQFggzMAE&amp;amp;url=http%3A%2F%2Fwww.vpri.org%2Fpdf%2Ftr2011001_final_worlds.pdf&amp;amp;usg=AOvVaw3yoCNzpwaucg8RngBkVX5n&quot;&gt;Worlds, Alan kay&lt;/a&gt; ver también &lt;a href=&quot;http://www.vpri.org/pdf/tr2008003_experimenting.pdf&quot;&gt;http://www.vpri.org/pdf/tr2008003_experimenting.pdf&lt;/a&gt; para una implementación en JS (2008)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Cargo Cult Science de Feynman&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://meaningness.com/metablog/upgrade-your-cargo-cult&quot;&gt;Upgrade your cargo cult for the win&lt;/a&gt; (relacionado con el anterior)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The Humble programmer de Dijkstra&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;On Building systems that will fail de Corbato&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Programming your own computer, by Alan Kay&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Natural Language Input for a Computer Problem Solving System&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A Few Useful Things to Know about Machine Learning&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Modeling Curiosity in a Mobile Robot for Long-Term Autonomous Exploration and Monitoring&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Computers Are Social Actors y un estudio que ahonda en este tema diferenciando el medio: Social Responses to Computers in Cloud Computing Environment: The Importance of Source Orientation&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Hexastore: Sextuple Indexing for Semantic Web Data Management, comentado por el creador de Redis aquí: https://redis.io/topics/indexes#representing-and-querying-graphs-using-an-hexastore&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Elephants don’t play chess&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;On the Origin of Deep Learning&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://arbor.revistas.csic.es/index.php/arbor/issue/view/149/showToc&quot;&gt;Número de la revista Arbor del CSIC sobre Alan Turing&lt;/a&gt;, incluye el ensayo de Bruce Wilcox sobre suzzette&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://juanmirod.github.io/public/out-of-the-tarpit.pdf&quot;&gt;Out of the tarpit&lt;/a&gt; Y mi reseña sobre este paper &lt;a href=&quot;http://juanmirod.github.io/2018/01/07/out-of-the-tarpit.html&quot;&gt;aquí&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://cacm.acm.org/magazines/2010/2/69354-a-few-billion-lines-of-code-later/fulltext#FNA&quot;&gt;A Few Billion Lines of Code Later: Using Static Analysis to Find Bugs in the Real World&lt;/a&gt; Genial paper sobre los problemas de escalar un producto a un público amplio y sobre lenguajes de programación. Los autores desarrollaron un sistema de analisis estático de errores quw funcionaba bastante bien en el laboratorio tomando algunos repositorios grandes de código abierto como el del kernel de linux. Al comercializar el producto se enfrentaron a toda una nueva categoria de problemas. Cada cliente tenia un metodo de build diferente y usaba un compilador de C diferente.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;“How do we run your tool?”&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;blockquote&gt;
      &lt;p&gt;“Just type ‘make’ and we’ll rewrite its output.”&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;blockquote&gt;
      &lt;p&gt;“What’s ‘make’? We use ClearCase.”&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;blockquote&gt;
      &lt;p&gt;“Uh, What’s ClearCase?”&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;p&gt;Otra gran cita que resume no solo el problema que tenian con el analisis estatico sino el problema del desarrollo software en general:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;You can’t check code you can’t parse. Checking code deeply requires understanding the code’s semantics. The most basic requirement is that you parse it. Parsing is considered a solved problem. Unfortunately, this view is naïve, rooted in the widely believed myth that programming languages exist.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;/public/papers/Goody-The_consequences_of_literacy.pdf&quot;&gt;On the concecuences of literacy&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Introducción a programación lógica con Prolog</title>
   <link href="http://juanmirod.github.io/2018/07/14/introduccion-a-prolog.html"/>
   <updated>2018-07-14T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2018/07/14/introduccion-a-prolog</id>
   <content type="html">&lt;p&gt;El lenguaje de programación Prolog es el lenguaje más conocido de programación lógica. La programación lógica es un tipo de programación declarativa que nos permite modelar nuestro problema en base a una serie de hechos y predicados que, aplicados a la entrada del usuario, permiten al intérprete inferir automáticamente la solución. Esta es la parte más importante: en prolog no decimos al programa cómo obtener la solución, solo definimos los hechos que sabemos que son ciertos y los predicados que definen las reglas del sistema. Es el motor lógico del intérprete el que, mediante la aplicación de los predicados, explorará el espacio de búsqueda que hemos creado en nuestro modelo para tratar de encontrar una solución.&lt;/p&gt;

&lt;p&gt;En este post voy a tratar de presentar las herramientas principales del lenguaje y mostrar algunos ejemplos, además de añadir referencias y biliografía para poder profundizar en el tema.&lt;/p&gt;

&lt;p&gt;Entorno de desarrollo y editor para Prolog: &lt;a href=&quot;http://www.swi-prolog.org/&quot;&gt;Swi-prolog&lt;/a&gt;
La instalación para Ubuntu es tan sencilla como añadir un PPA y usar apt-get para instalar el entorno (http://www.swi-prolog.org/build/PPA.txt):&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-add-repository ppa:swi-prolog/stable
    &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update
    &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;swi-prolog

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para arrancar el intérprete de Prolog, bastará con escribir &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prolog&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; prolog
Welcome to SWI-Prolog &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;threaded, 32 bits, version 7.6.4&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;legal details.

For online &lt;span class=&quot;nb&quot;&gt;help &lt;/span&gt;and background, visit http://www.swi-prolog.org
For built-in &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;, use ?- &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Topic&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; or ?- apropos&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Word&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;

?-

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Como indica el mensaje de bienvenida, podemos escribir, por ejemplo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;help(introduction).&lt;/code&gt; y swi-prolog nos mostrará una ventana con el manual de ayuda.&lt;/p&gt;

&lt;p&gt;En prolog tenemos dos piezas elementales para construir nuestros programas. Los &lt;em&gt;hechos&lt;/em&gt; y los &lt;em&gt;predicados&lt;/em&gt;. Los hechos son axiomas o constantes que el sistema tomará como ciertos y usará, junto con los predicados, para encontrar soluciones a las peticiones que le planteemos.&lt;/p&gt;

&lt;p&gt;Por ejemplo, si añadimos un hecho que diga que Juan es amigo de Patricia y el predicado que dice que los amigos de Juan son mis amigos:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; amigos.pl &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/
amigo&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;juan, patricia&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
amigo&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;yo, X&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; :- amigo&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;juan, X&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para cargar una serie de ficheros en el intérprete basta con escribir sus nombres, sin extensión, entre corchetes, separados con comas.&lt;/p&gt;

&lt;p&gt;Antes de cargar el código del ejemplo, veamos que está pasando:&lt;/p&gt;

&lt;p&gt;X es una variable, las variables empiezan por mayúscula y prolog tratará de sustituirlas por alguna constanque que haya en un hecho para ver si se cumple el predicado.&lt;/p&gt;

&lt;p&gt;Por ejemplo, podemos preguntar a Prolog si patricia es mi amiga &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amigo(yo, patricia).&lt;/code&gt;, prolog sustituirá la X por patricia y luego tratará de ver si hay algún predicado o algún hecho que permita confirmar que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amigo(juan,patricia).&lt;/code&gt; como tenemos un hecho que es exactamente así, prolog responderá afirmativamente.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;? - &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;amigos].
? - amigo&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;yo, patricia&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
true.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Un ejemplo algo más interesante, traducido de &lt;a href=&quot;http://kti.mff.cuni.cz/~bartak/prolog/learning.html&quot;&gt;Guide to prolog programming&lt;/a&gt; que muestra cómo modelar algunas relaciones familiares. Una vez introducidos los hechos, el intérprete puede inferir respuestas a preguntas usando los predicados, por ejemplo para responder quién es la madre de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paul&lt;/code&gt; o saber si &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paul&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;adam&lt;/code&gt; son hermanos.&lt;/p&gt;

&lt;div class=&quot;language-prolog highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cm&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;familia.pl&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;*/&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; Hechos &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;*/&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;hombre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;adam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;hombre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;peter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;hombre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;paul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;mujer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;mary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;mujer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;eve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;

&lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;adam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;peter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;eve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;peter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;adam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;paul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;mary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;paul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; predicados &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;*/&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;padre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;hombre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;madre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;mujer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;

&lt;span class=&quot;ss&quot;&gt;es_padre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;padre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;es_madre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;madre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;

&lt;span class=&quot;ss&quot;&gt;hijo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;hombre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;hija&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;mujer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;

&lt;span class=&quot;ss&quot;&gt;hermanos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;ss&quot;&gt;tio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;hombre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;hermanos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;tia&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;mujer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;hermanos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;

&lt;span class=&quot;ss&quot;&gt;descendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;descendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ascendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;descendiente&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-prolog highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;familia&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;madre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;paul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;mary&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;?-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;hermanos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;paul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;peter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;?-&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;padre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;adam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;paul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Una buena introducción al lenguaje es &lt;a href=&quot;/public/prolog.pdf&quot;&gt;este tutorial de la universidad de Granada&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Sobre Github, Microsoft y el desarrollo software</title>
   <link href="http://juanmirod.github.io/2018/06/04/github-microsoft.html"/>
   <updated>2018-06-04T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2018/06/04/github-microsoft</id>
   <content type="html">&lt;p&gt;Ya es oficial que &lt;a href=&quot;https://twitter.com/TechCrunch/status/1003624558321176577&quot;&gt;Microsoft ha comprado Github&lt;/a&gt; y hoy parece que no se hable de otra cosa en las comunidades de desarrolladores. Por un lado están los desarrolladores que piensan que lo ven como una mala señal:&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;My thoughts on GitHub...&lt;br /&gt;&lt;br /&gt;Microsoft in 2018 isn&amp;#39;t an evil monopolist anymore. They&amp;#39;ve actually invested heavily in open source, recently becoming the #1 contributor on GitHub including to many projects that are not their own (e.g. &lt;a href=&quot;https://twitter.com/electronjs?ref_src=twsrc%5Etfw&quot;&gt;@electronjs&lt;/a&gt;) but there are some downsides. 1/10&lt;/p&gt;&amp;mdash; 🇺🇸 FΞR😮SS  ❝ feross ❞ (@feross) &lt;a href=&quot;https://twitter.com/feross/status/1003735951422582785?ref_src=twsrc%5Etfw&quot;&gt;June 4, 2018&lt;/a&gt;&lt;/blockquote&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;It&amp;#39;s in the DNA of every company to generate profit for its owners, and this truth will eventually bleed through all the superficial kindness on which they built their community into an empire.&lt;br /&gt;&lt;br /&gt;RIP &lt;a href=&quot;https://twitter.com/hashtag/GitHub?src=hash&amp;amp;ref_src=twsrc%5Etfw&quot;&gt;#GitHub&lt;/a&gt;&lt;br /&gt;2008 - 2018&lt;br /&gt; &lt;a href=&quot;https://t.co/nzXXqsVs7b&quot;&gt;https://t.co/nzXXqsVs7b&lt;/a&gt;&lt;/p&gt;&amp;mdash; André Staltz (@andrestaltz) &lt;a href=&quot;https://twitter.com/andrestaltz/status/1003397603424391168?ref_src=twsrc%5Etfw&quot;&gt;June 3, 2018&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;Y por otro los que dicen: “Microsoft ha cambiado, la adquisición no es necesariamente mala, seguro que trae muchas mejoras para Github”:&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Seems like the LinkedIn acquisition is going well so far. I&amp;#39;d be willing to give them the benefit of the doubt. Especially with Satya at the helm.&lt;/p&gt;&amp;mdash; MICHAEL JACKSON (@mjackson) &lt;a href=&quot;https://twitter.com/mjackson/status/1003427703758860288?ref_src=twsrc%5Etfw&quot;&gt;June 4, 2018&lt;/a&gt;&lt;/blockquote&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Friendly reminder that git is open source, but GitHub *isn’t*.&lt;br /&gt;&lt;br /&gt;Also, while I don’t like Windows, Microsoft has a track of making great software for developers. So I’m not concerned&lt;/p&gt;&amp;mdash; Belén 😱 (@ladybenko) &lt;a href=&quot;https://twitter.com/ladybenko/status/1003529634162593792?ref_src=twsrc%5Etfw&quot;&gt;June 4, 2018&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;Otros, dicen que no hay que preocuparse porque pase lo que pase, siempre nos quedan los repos de git y podemos mudarnos a otro sitio:&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;This is the main reason I don&amp;#39;t find the Microsoft / github acquisition to be that much of a worry &lt;a href=&quot;https://t.co/lw4zRz55pL&quot;&gt;https://t.co/lw4zRz55pL&lt;/a&gt;&lt;/p&gt;&amp;mdash; Martin Fowler (@martinfowler) &lt;a href=&quot;https://twitter.com/martinfowler/status/1003678870556626945?ref_src=twsrc%5Etfw&quot;&gt;June 4, 2018&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;Personalmente creo que pecamos muchas veces de inocentes si decimos que tenemos los repos o que Microsoft es una compañía igual que Github.&lt;/p&gt;

&lt;p&gt;En el primer caso, &lt;strong&gt;el potencial de Github no es que guarde tu repo en la nube, eso o hace bitbucket, gitlab y otras tantas y lo hacía sourceforge mucho antes que ellos. El potencial de Github es como herramienta de gestión de proyectos y de colaboración&lt;/strong&gt; y eso es código cerrado y que no podemos duplicar fácilmente. Por otra parte Microsoft no es el mismo tipo de compañía que Github. Microsoft es una plataforma de software para b2b y b2c, y sus intereses están directamente relacionados con Windows y Azure, mientras que Github era agnóstica en cuanto a tu sistema operativo y la nube que uses para tus proyectos.&lt;/p&gt;

&lt;p&gt;Sobre el hecho de que Microsoft es una plataforma y cómo eso dirige sus decisiones, puedes leer más en &lt;a href=&quot;https://stratechery.com/2018/the-bill-gates-line/&quot;&gt;stratechery&lt;/a&gt;. Microsoft tiene una &lt;a href=&quot;https://en.wikipedia.org/wiki/Embrace%2C_extend%2C_and_extinguish&quot;&gt;conocida historia de EEE&lt;/a&gt; y que ahora hayan cambiado de CEO y hayan abrazado el OSS para muchos no es más que una bonita emboltura o un sapo que se han tenido que tragar para volver a ejecutar la misma estrategia. Con Github, Microsoft completa un camino en el que lleva trabajando años, ahora tienen el control sobre las principales herramientas de desarrollo a nivel mundial:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Controlan el principal lenguaje que compila a JavaScript, TypeScript, que se ha convencido a gran parte de los desarrolladores web y es especialmente afín a los desarrolladores de .Net&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Controlan VSCode, que se ha convertido en el editor más popular por méritos propios, pero que no es más que el hermano pequeño de Visual Studio, más ligero y más amigable, pero que cada día se parece más a su hermano mayor en cuanto a tamaño y a sobrecarga de funcionalidades.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Controlan Electron, una de las principales plataformas de desarrollo de aplicaciones de escritorio, que utiliza las mismas tecnologías que la web.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Y ahora controlan Github, la principal plataforma de colaboración en el mundo del desarrollo.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si algo nos ha enseñado la historia es que si pones demasiado poner en las manos de una sola persona o organización, tarde o temprano actuará en su propio beneficio y de forma despótica y llevándose por delante lo que haga falta.&lt;/p&gt;

&lt;p&gt;Si algo más hemos aprendido en la corta historia de la informática es que, cuando eso ocurra, los desarrolladores volveremos a implementar una opción libre en la que podamos hackear sin tener que pagar o rendir cuentas a nadie. Porque podemos, porque sabemos hacerlo y porque las grandes compañías al final siempre acaban moviendose a otro ritmo y nosotros queremos poder hurgar en el código. Aunque siempre haya Microsofts y Apples y IBMs, también siempre habrá Richard Stallmans, Linus Torvalds y Tim Berners Lees.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Reseña ¿Qué es la ética informática?</title>
   <link href="http://juanmirod.github.io/2018/03/06/etica-informatica.html"/>
   <updated>2018-03-06T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2018/03/06/etica-informatica</id>
   <content type="html">&lt;p&gt;Nuestra profesión es muy joven, y a la vez la barrera de entrada es muy baja.&lt;/p&gt;

&lt;p&gt;Para ser médico necesitas estudiar una carrera que dura 6 años y es muy exigente, luego comienzas a trabajar en un periodo legal de aprendizaje que dura entre 3 y 5 años, durante el cual se considera que no eres totalmente responsable sino que estás supervisado. Además tienes que colegiarte y tener un seguro que cubra tu actividad profesional, y encima de todo eso tienes el juramento hipocrático y toda una serie de valores y estatus asociados que te hacen considerar tus acciones y sus repercusiones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Para ser informático solo necesitas un ordenador y saber leer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sin conocimientos previos puedes crear una cuenta en wordpress.com o en AWS o en mil sitios parecidos y tendrás un millón de guías de cómo crear tu propia página web, cómo añadir funcionalidad a esa web, cómo cambiar los estilos… El flujo de acciones nunca para, todo el mundo habla sobre el “Cómo”, pero tenemos muy poco discurso, y mucho menos normativa, sobre el “Por qué” o sobre las consecuencias de nuestro trabajo.&lt;/p&gt;

&lt;p&gt;Pero inevitablemente, cuando nuestro proyecto deja de ser un prototipo o una idea puramente técnica, &lt;strong&gt;cuando lo publicamos y entra en contacto con la realidad, surgirán gran cantidad de dudas y conflictos. ¿Estamos guardando datos personales de los usuarios? ¿Puede nuestro programa utilizarse para usos maliciosos, incluso aunque no fuera nuestra intención o vaya en contra del “espíritu” del programa? ¿Estamos avisando adecuadamente a los usuarios de los problemas que podrían producirse? ¿Tiene el usuario libertad para usar y modificar nuestro código?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Si tienes la suerte de haber hecho la carrera tal vez hayas tenido alguna asignatura donde se haya tocado el tema. Yo no tuve ninguna asignatura de ética en la mía, pero en la adaptación al grado he cursado &lt;a href=&quot;http://juanmirod.github.io/2017/08/16/etica-y-legislacion.html&quot;&gt;Ética y legislación&lt;/a&gt; y ahora vengo a hablar de nuevo del tema, no solo por que me interesa, si no porque estoy leyendo el texto &lt;a href=&quot;/public/Ética_Informática_Guibert.pdf&quot;&gt;¿Qué es la ética informática? de José M. Guibert Ucín&lt;/a&gt; como lectura obligatoria en otra asignatura.&lt;/p&gt;

&lt;p&gt;En ese texto, el autor hace un repaso de los diferentes campos en los que es necesaria la ética en los proyectos informáticos para luego hacer una defensa humanista de la informática:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;La accesibilidad, la distribución equitativa, la justicia social, el trabajo autorrealizante, el crecimiento sostenido, etc. son valores que están en juego en la implantación de las nuevas
tecnologías. Como contribuciones problemáticas de las tecnologías de la información, está el
papel que juegan en la globalización de la economía, las fusiones empresariales o en el aumento continuo del abismo entre los países desarrollados y en desarrollo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tras mostrar la necesidad de la ética en la informática y los puntos conflictivos, Guibert hace un repaso del estado de la literatura y la enseñanza de la ética informática. La conclusión es que los pasos que se han dado son demasiado débiles: necesitamos de una mayor concienciación y un mayor estudio de las cuestiones éticas que supone el desarrollo de las tecnologías de la información y las comunicaciones y necesitamos también dar más puntos de vista sobre los actuales, muy individualistas y centrados en la responsabilidad del individuo y no en la de las empresas o en las repercusiones en la sociedad del desarrollo tecnológico actual.&lt;/p&gt;

&lt;p&gt;La EI no es sólo hablar de si debemos ser más o menos rigurosos en el desempeño de nuestro trabajo, sino también de cómo plantear soluciones y alternativas a las desigualdades y discriminaciones que genera.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>¿Por qué Linux?</title>
   <link href="http://juanmirod.github.io/2018/02/15/porque-linux.html"/>
   <updated>2018-02-15T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2018/02/15/porque-linux</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/public/img/gnulinux.jpg&quot; alt=&quot;Logos de GNU y Linux&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Desde hace años uso Linux, tanto en el trabajo como en casa. Cambié a Linux gradualmente, no soy una persona de extremos y tardo un poco en sacarle el jugo a las cosas.&lt;/p&gt;

&lt;p&gt;Al principio solo era curiosidad por probar un sistema operativo más seguro y más fiable. La primera vez que probé la línea de comandos en la facultad me pareció todo anticuado y sin sentido, pero poco a poco fui familiarizándome con los comandos para manejar archivos, con la estructura de directorios de Linux y con los gestores de paquetes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Poco a poco te das cuenta de que puedes modificar y configurar TODO. Linux no es simplemente un Sistema Operativo, es un sistema libre, que puedes leer, modificar y replicar.&lt;/strong&gt; Hay más código y documentación del que podrás leer, más comandos de los que puedes aprender, más libertad de la que podrías soñar con cualquier otro sistema operativo.&lt;/p&gt;

&lt;p&gt;He escrito comandos en una línea que me costaría cientos escribir en JavaScript o en Python para tener la misma funcionalidad. La línea de comandos tiene herramientas increíbles y lo mejor es que cuando aprendes algo puedes guardar el comando, o ponerlo en un script y lo tienes &lt;strong&gt;para siempre&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imaginemos una situación típica: Tienes un montón de fotos que quieres convertir a blanco y negro con un filtro concreto para ver como quedan, porque estás buscando la mejor o quieres decidir cuál imprimir o lo que sea. Abres tu programa de edición gráfico favorito (por ejemplo GIMP) seleccionas el filtro que quieres, los valores, ves como queda y guardas la foto. Si te sabes los atajos de teclado, tal vez guardar la foto o incluso abrir la siguiente foto para aplicarle el mismo filtro puede que sea un par de golpes de teclado. Si no, tienes que hacer todo esto otra vez para cada foto, persiguiendo iconos minúsculos con el ratón. De cualquier forma tienes que abrir, editar y guardar CADA FOTO. A veces haces click sin querer en la opción que no es, o te equivocas al guardar y machacas la foto original… Creo que es fácil que te resulte familiar esta escena. Lo que muchos pensamos cuando hacemos esto es &lt;strong&gt;“¿No hay una forma mejor? ¿Por que no puedo decirle al ordenador que haga con todas esas fotos lo que acabo de hacer con esa?”&lt;/strong&gt; La conclusión suele ser que el ordenador es imbécil, cuando no es así, simplemente estamos usando la herramienta errónea.&lt;/p&gt;

&lt;p&gt;En la línea de comandos buscas el comando una vez, lo pruebas, y podrás usarlo un millón de veces. Podrás usar un comodín para ejecutarlo sobre todas tus imágenes, o meterlo en un bucle, en un script, usarlo dentro de seis meses sobre una nueva remesa de fotografías simplemente invocando un alias.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Las posibilidades son infinitas, porque no dependes de una serie de acciones más o menos conocidas con el ratón, lo tienes escrito&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Las macros que no dependen del ratón, sino que guardan tus acciones y las ejecutan también son una solución, pero normalmente dependen del programa que las crea y no se pueden componer o exportar a otros programas. La línea de comandos es lo más universal que tenemos ahora mismo. Funciona igual en tu escritorio que en un servidor en AWS, puedes componer comandos de diferentes herramientas, puedes crear scripts y en resumen puedes hacer todo eso que creíais que el ordenador era demasiado tonto para hacer. Solo requiere un punto de vista diferente.&lt;/p&gt;

&lt;p&gt;En &lt;a href=&quot;/public/TLCL-09.12.pdf&quot;&gt;The Linux Comand Line (pdf)&lt;/a&gt;, William E. Shotts explica muy bien esa sensación de posibilidades sin límites, con una analogía con los Erector Construction Set (más conocidos como Mecano para mi generación)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Linux Is About Imagination&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;When I am asked to explain the difference between Windows and Linux, I often use a toy analogy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Windows is like a Game Boy. You go to the store and buy one all shiny new in the box. You take it home, turn it on and play with it. Pretty graphics, cute sounds. After a while though, you get tired of the game that came with it so you go back to the store and buy another one. This cycle repeats over and over. Finally, you go back to the store and say to the person behind the counter, “I want a game that does this!” only to be told that no such game exists because there is no “market demand” for it. Then you say, “But I only need to change this one thing!” The person behind the counter says you can’t change it. The games are all sealed up in their cartridges. You discover that your toy is limited to the games that others have decided that you need and no more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Linux, on the other hand, is like the world’s largest Erector Set. You open it up and it’s just a huge collection of parts. A lot of steel struts, screws, nuts, gears, pulleys, motors, and a few suggestions on what to build. So you start to play with it. You build one of the suggestions and then another. After a while you discover that you have your own ideas of what to make. You don’t ever have to go back to the store, as you already have everything you need. The Erector Set takes on the shape of your imagination. It does what you want. Your choice of toys is, of course, a personal thing, so which toy would you find more satisfying?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En &lt;a href=&quot;http://www.cryptonomicon.com/beginning.html&quot;&gt;In the begining was the command line&lt;/a&gt; Neal Stephenson compara los sistemas operativos con coches, y Linux con un tanque ligero, indestructible, que consume lo mismo que un coche y puede circular por ciudad, con voluntarios que lo mantienen y te explican cómo funciona, todo completamente gratis…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/light_tank.jpg&quot; alt=&quot;Fotografía de un tanque ligero&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Imagine a crossroads where four competing auto dealerships are situated. One of them (Microsoft) is much, much bigger than the others. It started out years ago selling three-speed bicycles (MS-DOS); these were not perfect, but they worked, and when they broke you could easily fix them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;There was a competing bicycle dealership next door (Apple) that one day began selling motorized vehicles–expensive but attractively styled cars with their innards hermetically sealed, so that how they worked was something of a mystery.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;The big dealership responded by rushing a moped upgrade kit (the original Windows) onto the market. This was a Rube Goldberg contraption that, when bolted onto a three-speed bicycle, enabled it to keep up, just barely, with Apple-cars. The users had to wear goggles and were always picking bugs out of their teeth while Apple owners sped along in hermetically sealed comfort, sneering out the windows. But the Micro-mopeds were cheap, and easy to fix compared with the Apple-cars, and their market share waxed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Eventually the big dealership came out with a full-fledged car: a colossal station wagon (Windows 95). It had all the aesthetic appeal of a Soviet worker housing block, it leaked oil and blew gaskets, and it was an enormous success. A little later, they also came out with a hulking off-road vehicle intended for industrial users (Windows NT) which was no more beautiful than the station wagon, and only a little more reliable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Since then there has been a lot of noise and shouting, but little has changed. The smaller dealership continues to sell sleek Euro-styled sedans and to spend a lot of money on advertising campaigns. They have had GOING OUT OF BUSINESS! signs taped up in their windows for so long that they have gotten all yellow and curly. The big one keeps making bigger and bigger station wagons and ORVs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;On the other side of the road are two competitors that have come along more recently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;One of them (Be, Inc.) is selling fully operational Batmobiles (the BeOS). They are more beautiful and stylish even than the Euro-sedans, better designed, more technologically advanced, and at least as reliable as anything else on the market–and yet cheaper than the others.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;With one exception, that is: Linux, which is right next door, and which is not a business at all. It’s a bunch of RVs, yurts, tepees, and geodesic domes set up in a field and organized by consensus. The people who live there are making tanks. These are not old-fashioned, cast-iron Soviet tanks; these are more like the M1 tanks of the U.S. Army, made of space-age materials and jammed with sophisticated technology from one end to the other. But they are better than Army tanks. They’ve been modified in such a way that they never, ever break down, are light and maneuverable enough to use on ordinary streets, and use no more fuel than a subcompact car. These tanks are being cranked out, on the spot, at a terrific pace, and a vast number of them are lined up along the edge of the road with keys in the ignition. Anyone who wants can simply climb into one and drive it away for free.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Customers come to this crossroads in throngs, day and night. Ninety percent of them go straight to the biggest dealership and buy station wagons or off-road vehicles. They do not even look at the other dealerships.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Of the remaining ten percent, most go and buy a sleek Euro-sedan, pausing only to turn up their noses at the philistines going to buy the station wagons and ORVs. If they even notice the people on the opposite side of the road, selling the cheaper, technically superior vehicles, these customers deride them cranks and half-wits.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Batmobile outlet sells a few vehicles to the occasional car nut who wants a second vehicle to go with his station wagon, but seems to accept, at least for now, that it’s a fringe player.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;The group giving away the free tanks only stays alive because it is staffed by volunteers, who are lined up at the edge of the street with bullhorns, trying to draw customers’ attention to this incredible situation. A typical conversation goes something like this:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hacker with bullhorn: “Save your money! Accept one of our free tanks! It is invulnerable, and can drive across rocks and swamps at ninety miles an hour while getting a hundred miles to the gallon!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Prospective station wagon buyer: “I know what you say is true…but…er…I don’t know how to maintain a tank!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Bullhorn: “You don’t know how to maintain a station wagon either!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Buyer: “But this dealership has mechanics on staff. If something goes wrong with my station wagon, I can take a day off work, bring it here, and pay them to work on it while I sit in the waiting room for hours, listening to elevator music.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Bullhorn: “But if you accept one of our free tanks we will send volunteers to your house to fix it for free while you sleep!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Buyer: “Stay away from my house, you freak!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Bullhorn: “But…”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Buyer: “Can’t you see that everyone is buying station wagons?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por último, quería volver a incidir en la propiedad más destacable de Linux, que cada vez parece más ahogada en esta nueva era de código abierto que no es código libre: Linux es Software Libre, no solo puedes ver el código, puedes ejecutarlo, copiarlo, distribuirlo. Está ahí para que todos podamos aprovecharlo y construir encima de él, ese es su gran valor y su gran fortaleza.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Comparando objetos por valor</title>
   <link href="http://juanmirod.github.io/2018/01/09/comparacion-objetos-por-valor.html"/>
   <updated>2018-01-09T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2018/01/09/comparacion-objetos-por-valor</id>
   <content type="html">&lt;p&gt;Una de las típicas quejas de los programadores sobre javascript es que, aunque permite crear objetos de forma literal:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a property&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;La comparación de objetos no es por valor, si no que es referencial, es decir, dos objetos no son iguales desde el punto de vista del comparador de igualdad a no ser que sean el mismo objeto:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a property&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a property&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;another property&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// false&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true c apunta al mismo objeto, la asignación no ha clonado el objeto&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Es decir, aunque en la sintaxis pueda parecer que los objetos son valores como en otros lenguajes funcionales (LISP o Haskell por ejemplo) en realidad solo son punteros a los objetos, al estilo de lenguajes imperativos como C. Esta disonancia empeora si además usamos el operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;==&lt;/code&gt; que hace casting de forma automática de los argumentos para realizar la comparación, con lo que obtenemos cosas como:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// false&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true wtf?&lt;/span&gt;

&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// false &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// false &lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Es difícil razonar con el lenguaje haciendo transformaciones implícitas y no obvias a simple vista, pero hay una solución muy sencilla para comprarar objetos literales en javascript por valor:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a property&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a property&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON.stringify&lt;/code&gt; convertirá el objeto a una cadena, podemos usarlo con objetos anidados sin problemas mientras no haya funciones dentro de las propiedades o propiedades cíclicas. Los objetos literales nos permiten estructurar nuestros datos y acceder fácilmente a ellos, siempre han sigo muy utilizados en JavaScript y más desde el auge de las APIs JSON, pero aún más desde que llegaron React y Redux a revolucionar la comunidad y promover el uso de funciones puras, inmutabilidad y objetos literales para manejar nuestras aplicaciones.&lt;/p&gt;

&lt;p&gt;Crear una función isEqual JSON.stringify es trivial:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;isEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;isEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a property&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;a property&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;isEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Pero ¿y eso no será muy lento?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Es algo más lento que la implementación de Underscore, pero debemos recordar que:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Premature optimization is the root of all evil – &lt;a href=&quot;http://wiki.c2.com/?PrematureOptimization&quot;&gt;DonaldKnuth&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Desde luego, si usas alguna de estas o otra librería funcional que tenga este método: úsalo, la implementación está más que testeada y optimizada, es una apuesta segura.&lt;/p&gt;

&lt;p&gt;Pero si no tienes esta dependencia en tu proyecto, a lo mejor no quieres añadirla.&lt;/p&gt;

&lt;p&gt;Y &lt;strong&gt;a no ser que realmente vayamos a usar esta operación decenas de miles de veces por segundo de forma continuada, no nos merezce la pena el peso extra y la dependencia que añadimos a la aplicación&lt;/strong&gt;. De todas formas, para poder comparar, enlazo a jsperf con un benchmark que aparece nada más buscar el tema en google: &lt;a href=&quot;https://jsperf.com/lo-dash-vs-underscore-vs-json-stringify-isequal&quot;&gt;https://jsperf.com/lo-dash-vs-underscore-vs-json-stringify-isequal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La solución de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON.stringify&lt;/code&gt; se entiende a simple vista por cualquier programador de JavaScript, no tiene ninguna lógica oculta que nos haga preguntarnos que haría en tal o cual caso y si es necesario siempre se puede sustituir más adelante por algo más sofisticado.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Reseña Out of the Tarpit</title>
   <link href="http://juanmirod.github.io/2018/01/07/out-of-the-tarpit.html"/>
   <updated>2018-01-07T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2018/01/07/out-of-the-tarpit</id>
   <content type="html">&lt;p&gt;Conforme leo algunos papers quiero ir subiéndo los más interesantes al blog y comentándolos, aunque sea de pasada, para ayudarme a recordarlos y tenerlos a mano para volver a ellos cuando quiera. La idea no es mía, la he tomado de sitios como &lt;a href=&quot;https://blog.acolyer.org&quot;&gt;the morning paper&lt;/a&gt; o el &lt;a href=&quot;http://worrydream.com/refs/&quot;&gt;directorio de Bret Victor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/public/out-of-the-tarpit.pdf&quot;&gt;Out of the tarpit - Mosley and Marks 2006&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Siempre me gustan este tipo de ensayos que hablan de el trabajo del programador, y cómo todos coinciden en que hay que tratar de conseguir la mayor simplicidad posible, siendo el escenario ideal la programación declarativa. Este paper en concreto, además, se centra en uno de los temas favoritos de los desarrolladores: como crear un framework de trabajo ideal, que permita ese estilo simple y declarativo de desarrollo. Ha tenido bastante repercusión en la industria y lo he visto citado más de una vez por conocidos desarrolladores. Hago un resumen de las ideas claves, aunque nada como leer el paper tranquilamente para que cale bien.&lt;/p&gt;

&lt;h2 id=&quot;qué-es-la-simplicidad&quot;&gt;¿Qué es la simplicidad?&lt;/h2&gt;

&lt;p&gt;La simplicidad para el desarrollador es siempre como un espejismo. Como una ilusión optica que sabes que no puede ser verdad. Para los ojos de los no desarrolladores todo debería ser tan fácil como especificar en unas cuantas frases o gráficos el problema y el ordenador debería poder hacer el resto. Para eso los tenemos, para hacer todo cálculo que no sea puramente creativo.&lt;/p&gt;

&lt;p&gt;O eso parece. Cuando te acercas a los detalles, cuando te pones a programar, te das cuenta de que necesitas ser mucho más concreto y todos esos pequeños detalles que se obviaron en la descripción inicial son imprescindibles para tener un sistema que funcione y son el 80% del trabajo.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Por ejemplo, un cliente normal solo piensa en “guarda estos datos en la base de datos” Pero nosotros tenemos que decidir si en una base de datos relacional o de documentos por ejemplo (¿Postgress o MySQL? ¿Mongo, MariaDB, Couch, Dynamo? ¿Redis, Memcache? …), cómo normalizar los datos para almacenarlos, qué índices deberemos crear para facilitar las búsquedas, qué tipos de datos tienen los diferentes campos que se quieren guardar, que tamaño total tienen los datos y si se podrán mantener en RAM, se deben cachear o no, cómo se va a acceder a esos datos posteriormente y si deben replicarse a lo largo y ancho del mundo, si queremos que el almancenamiento sea immutable tipo log o mutable, qué permisos y qué privacidad tienen los datos, ¿quién debe poder acceder a ellos? ¿Quien no debería poder? ¿Hay leyes que protejan estos datos? ¿Pueden ser un atractivos para un atacante? etc, etc, etc…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Algunas de esas preguntas debe de responderlas el cliente o el proyecto, si no fueron respondidas en las especificaciones, deberíamos preguntar directamente para saber qué hacer. Pero otras dependen únicamente del hecho de que estamos representando los datos en ordenadores que tienen limitaciones físicas y temporales. Esto último es lo que en Out of the tarpit llaman &lt;em&gt;complejidad accidental&lt;/em&gt;. Es decir, el desarrollador debería poder escapar de toda esa complejidad derivada de estar representando los datos como 1’s y 0’s centro de un disco magnético o de una matriz de transistores. Deberíamos poder ignorar los detalles sobre velocidad de acceso, espacio, tipos de datos (a nivel de bytes) y demás limitaciones del hardware para centrarnos en el problema en sí.&lt;/p&gt;

&lt;h2 id=&quot;cómo-lo-conseguimos&quot;&gt;¿Cómo lo conseguimos?&lt;/h2&gt;

&lt;p&gt;La propuesta de los autores es la Programación Funcional Relacional (FRP en el original) que es un término que han inventado ellos para el framework que proponen. Pero antes de llegar a la propuesta final, dejan claro que es una cuestión de disciplina y de limitar la expresividad del/los lenguajes de programación para buscar la simplicidad.&lt;/p&gt;

&lt;p&gt;Para darle autoridad a esta afirmación, a la necesidad de huir de la complejidad, los autores citan a grandes personalidades del desarrollo como Hoare, Backus, Corbato, Brooks y Dijsktra. En la actualidad, una de las principales personalidades del mundo del desarrollo que es conocido por seguir este mismo discurso es Rich Hickey, el creador de Clojure, y en especial su charla &lt;a href=&quot;https://www.infoq.com/presentations/Simple-Made-Easy&quot;&gt;“Simple made easy”&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El de &lt;strong&gt;la simplicidad es un mantra repetido a lo largo y ancho del mundo del desarrollo, KISS, YAGNI, POJO son algunos acrónimos que se vienen a la mente&lt;/strong&gt;. Pero cómo conseguirla no es tan sencillo y en este documento Mosley y Marks intentan dar una respuesta mediante una arquitectura que huya de la complejidad y del acoplamiento.&lt;/p&gt;

&lt;p&gt;El paper identifica dos fuentes principales de complejidad que enturbia el código: estado y lógica de control. En un &lt;em&gt;mundo ideal&lt;/em&gt; la lógica de control sería totalmente prescindible y el único estado necesario sería la entrada del usuario, todo lo demás debería poderse derivar mediante reglas declarativas hasta obtener un resultado, de forma parecida a una demostración matemática. De hecho una de las referencias y de las herramientas del framework propuesto es la programación lógica, en la que el programador declara una serie de reglas o hechos que el compilador tomará como verdades absolutas o axiomas que podrá usar para derivar el resultado del programa junto con la entrada del usuario.&lt;/p&gt;

&lt;p&gt;Aun así, cualquier problema no trivial tendrá cierta dificultad, esta es la &lt;em&gt;complejidad esencial&lt;/em&gt;: aquella innerente al problema que estamos tratanto, suponiendo que los cálculos se hacen de forma ideal y no limitados por el hardware y los problemas del mundo real.&lt;/p&gt;

&lt;p&gt;Pero no vivimos en un mundo ideal, los ordenadores son reales y no imaginarios y si queremos ejecutar algo en ellos tenemos que atenernos al marco que tenemos. Las dificultades que surgen de representar el problema en el ordenador y poder interactuar con él es lo que los autores llaman &lt;em&gt;complejidad accidental&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Para atomizar y atacar esta complejidad se basan en dos principios: evitar la complejidad y separarla cuando no puedes evitarla.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evitarla quiere decir no crear ningún estado o lógica que no sea absolutamente necesaria para resolver el problema,&lt;/strong&gt; todo estado que se pueda derivar de la entrada, deberá derivarse y no almacenarse a no ser que sea realmente necesario para comprender mejor el problema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separarla quiere decir que, si vemos que necesitamos ese estado o esa lógica de control, debemos separarlo a donde pertenece dentro de la arquitectura.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Esto así dicho suena más fácil de lo que es, ya que al final la responsabilidad recae en la diligencia del programador. Para ayudar en esta labor se establece que la arquitectura debe de seguir este diagrama:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/frp.png&quot; alt=&quot;Diagrama FRP&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Para mi este es un diagrama más importante que el posterior de FRP porque es más genérico: tenemos un lenguage y una infraestructura que nos van a permitir expresar el estado esencial en base a una serie de axiomas independientes del resto del programa, es decir que los cambios en el resto del programa nunca deben suponer cambios en el estado esencial. Si el estado esencial cambia, seguramente se vean afectados los otros componentes, pero este núcleo no debe verse afectados por cambios en el exterior.&lt;/p&gt;

&lt;p&gt;De forma parecida, la lógica esencial solo puede verse afectada por cambios en el estado esencial, pero no por cambios en el el control y estado accidental o en la infraestructura y la logica y el estado accidentales son dependientes tanto de la lógica esencial como del estado esencial y sirven para conectarlos al mundo real.&lt;/p&gt;

&lt;p&gt;FRP es una de las muchas posibles implementaciones de esta idea. Usando el modelo relacional para definir el estado esencial y la programación funcional para la lógica se pretende crear esta separación de responsabilidades y así mantener un sistema simple y fácil de modificar.&lt;/p&gt;

&lt;p&gt;De ahí que la propuesta sea también usar varios lenguajes, muy restringidos, para cada parte del framework, para evitar que los programadores caigan en la tentación de &lt;em&gt;“acortar camino”&lt;/em&gt; mezclando lógica con estado. Un poco como CSS y HTML que son lenguajes muy restringidos y con una función concreta, salvo que en el caso del desarrollo web el control y el estado los gestionamos con JavaScript que es un lenguaje dinámico y muy laxo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;En este sentido me llama la atención que la propuesta sea tener lenguajes restringidos cuando la tendencia en todos los lenguajes es incorporar más y más funcionalidad.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Personalmente creo que el objetivo de tener un programa totalmente declarativo y funcional ayudaría mucho al desarrollo, pero no es la tendencia que veo en los lenguajes actuales o futuros. Lo que yo veo, extrapolando a partir del panorama actual, es lenguajes cada vez más ricos e intercambiables, cada vez más expresivos y que se pueden usar en cualquier situación. Ahora mismo hay una explosión de compiladores y traductores. Compilar Haskell o Clojure o Reason a JavaScript, C o C++ a wasm, compilar javascript a binario, Clojure sobre Java o sobre .NET, Crystal es como un Ruby que compila y es super rápido…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La idea es que no importa en el lenguaje que trabajes, pronto podrás hacer cualquier tipo de aplicación, para la web o fuera de ella, con cualquier lenguaje.&lt;/strong&gt; Veo los lenguajes de programación del futuro un poco como los lenguajes naturales: cada uno tendrá su lenguaje “nativo” o preferido y con él podrá hacer lo mismo que con cualquier otro. Por supuesto habrá bilingües y políglotas, y algunos lenguajes seguirán siendo mejor para algunas cosas y habrá dominios que estén completamente en un lenguaje, pero eso también pasa con los lenguajes humanos y esa es la tendencia que veo. Al final la complejidad del mundo real no se puede encasillar o domar y nosotros no somos máquinas. Pensar con restricciones no es nuestra forma natural de expresarnos y siempre tendemos a la solución que nos dé más libertad de expresión, esa es una de las razones del éxito de JavaScript o de que diferentes dialectos de LISP sigan usándose.&lt;/p&gt;

&lt;p&gt;Sin embargo sí que podemos ver una tendencia hacia una programación más funcional y más en la línea de lo que marca este paper. De hecho el paper tuvo una gran influencia en David Nolan, creador de Om, que a su vez influyó en Redux y hoy en día tenemos muchas aplicaciones web que tienen una única fuente de verdad, un store con el estado de la aplicación, de forma similar al &lt;em&gt;“estado esencial”&lt;/em&gt; del que hablábamos.&lt;/p&gt;

&lt;p&gt;Además, este estado sólo se puede modificar mediante el store para controlar que la lógica que modifica ese estado esté centralizada en los Reducers, de forma parecida al motor de lógica esencial del que habla el paper. Lo que nos falta es una infraestructura que cumpla las promesas del paper y es que, aunque React, Vue o Angular hagan la interacción con el DOM declarativa y nos permitan separar también la capa de presentación, la interacción del usuario todavía embarra mucho el código.&lt;/p&gt;

&lt;p&gt;Los Observables de RxJs mejoran también mucho esta experiencia y la hacen más funcional y fácil de componer, pero aun no tenemos una infraestructura que aúne todos estos elementos de forma simple y transparente al programador. Al contrario la &lt;em&gt;complejidad accidental&lt;/em&gt; de tener que combinar un lenguaje con variables no inmutables y las distintas librerías más el hecho de que todo esto debe transpilarse y empaquetarse para poder servirlo en la web hace que sea necesaria mucha disciplina para mantener esa complejidad accidental fuera del resto del sistema.&lt;/p&gt;

&lt;p&gt;Otros intentos de mejorar el desarrollo de aplicaciones y conseguir una buena separación de responsabilidades son Elm y ClojureScrip. Ambos lenguajes, aunque muy diferentes, pretenden esa simplidad gracias a la programación funcional y a la inmutabilidad de los datos y están, en mi opinión, un paso más cerca del objetivo. Veremos como evoluciona todo esto, pero ciertamente &lt;strong&gt;da la sensación de que estuviéramos en otro de esos grandes momentos de creación de nuevas ideas y lenguages, como ocurrió en los 50 y más tarde en los 80, pero con una masa crítica de desarrolladores mucho mayor&lt;/strong&gt;, lo que a la vez permite tener mucha más creatividad pero también que se de el fenómeno que comentaba antes de lenguajes sobredimensionados y programadores monolingües que no necesitan salir de su lenguaje o su estilo de programación para continuar desarrollando.&lt;/p&gt;

&lt;p&gt;Este me parece un ensayo importante para repasar muchos de los nuevos lenguajes y frameworks que hemos visto surgir en los últimos años. El desarrollo sigue evolucionando y tratando de alcanzar esa meta última de la simplicidad y el lenguaje declarativo ideal. Pero por el camino miles de programadores hacen su trabajo cada día ajenos a todas estas reglas y reflexiones, en lenguajes cada vez más potentes y polivalentes que les permiten no plantearse si realmente lo están haciendo bien. Para mi esta dicotomía siempre ha existido y siempre existirá, no es lo mismo programar por afición que profesionalmente, no es lo mismo desarrollar un producto que una solución SaaS. Cada proyecto tiene un lenguaje que se adapta mejor al problema y cada programador tiene un lenguaje favorito o que conoce mejor.&lt;/p&gt;

&lt;p&gt;No sé que vendrá en el futuro, pero lo que puedo tener seguro es que no será una única solución que lo resuelva todo y haga que todos trabajemos al unísono en una especie de paraíso de la programación donde resolvemos todos los problemas de forma declarativa. Out of the tarpit da muchas claves para mantener a raya la complejidad y el acoplamiento, que es algo que todos los programadores profesionales debemos tener en cuenta, pero queda un largo camino hasta que ideas así sean habituales en este magma informe que es el desarrollo de software.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Buenas prácticas en pruebas de software</title>
   <link href="http://juanmirod.github.io/2017/11/25/buenas-practicas-tests.html"/>
   <updated>2017-11-25T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/11/25/buenas-practicas-tests</id>
   <content type="html">&lt;p&gt;Como en todas las cosas complejas, no hay una respuesta concreta a la pregunta de cuántas pruebas son suficientes. Tener pruebas automáticas que evalúen el código constantemente es importante para tener seguridad a la hora de desarrollar y para no introducir errores con cada cambio. Pero la cantidad y el tipo de pruebas/tests dependerá del tipo de proyecto, la experiencia de los desarrolladores o el tipo de aplicación.&lt;/p&gt;

&lt;p&gt;No es lo mismo desarrollar el software de un marcapasos o del control de vuelo de un avión, que un software para gestionar una empresa pequeña que un juego de móvil. El dominio de la aplicación y el tiempo de respuesta que tenemos nos marcan cómo de crítico es un bug y cómo de importante es que no llegue a producción.&lt;/p&gt;

&lt;p&gt;Dicho esto, como siempre, es una cuestión de grises más que de blanco o negro. Pero como guía un poco de &lt;em&gt;perogrullo&lt;/em&gt;, dejo este listado de tipos de pruebas de software, ordenados de mejor a peor. Si no puedes conseguir el primero, intenta el segundo, y si no, el tercero y así…&lt;/p&gt;

&lt;h2 id=&quot;100-de-cobertura-un-sistema-de-integración-continua-y-un-sistema-de-logs-y-monitorización-completos&quot;&gt;100% de cobertura, un sistema de integración continua y un sistema de logs y monitorización completos&lt;/h2&gt;
&lt;p&gt;nos darán la seguridad de que ningún bug se nos escapa y además podemos reaccionar rápidamente ante cualquier incidencia&lt;/p&gt;

&lt;p&gt;Si no tenemos los sistemas de monitorización, pero tenemos integración continua, podremos reaccionar rápidamente ante cualquier incidencia de un cliente.&lt;/p&gt;

&lt;h2 id=&quot;100-de-cobertura-con-tests-automáticos-es-mejor-que-no-tener-100-de-cobertura&quot;&gt;100% de cobertura con tests automáticos es mejor que no tener 100% de cobertura&lt;/h2&gt;
&lt;p&gt;Si no tenemos 100%, una recomendación habitual a &lt;em&gt;ojo de buen cubero&lt;/em&gt; es mantenerse por encima del 75%&lt;/p&gt;

&lt;h2 id=&quot;escribir-los-test-antes-que-el-código-es-mejor-que-escribirlos-después&quot;&gt;Escribir los test antes que el código es mejor que escribirlos después&lt;/h2&gt;
&lt;p&gt;Escribir los tests antes asegura que nos ceñimos a los requisitos, que planteamos el problema en función que lo que queremos y no de lo que ya hemos programado y que en los tests no se introducen detalles de la implementación.&lt;/p&gt;

&lt;h2 id=&quot;escribir-los-tests-después-que-el-código-es-mejor-que-no-escribirlos-nunca&quot;&gt;Escribir los tests después que el código es mejor que no escribirlos nunca&lt;/h2&gt;

&lt;h2 id=&quot;muchos-tests-unitarios-y-algunos-de-integración-es-mejor-que-muchos-tests-de-integración-sin-tests-unitarios&quot;&gt;Muchos tests unitarios y algunos de integración es mejor que muchos tests de integración sin tests unitarios&lt;/h2&gt;
&lt;p&gt;Tener sólo tests de integración hace que sea muy difícil cubrir todas las posibilidades y son más costosos de escribir y más lentos, con lo que la tarea de manterlos se hace cada vez más difícil conforme el proyecto crece.&lt;/p&gt;

&lt;h2 id=&quot;algunos-tests-automáticos-es-mejor-que-ningún-test-automático&quot;&gt;Algunos tests automáticos es mejor que ningún test automático&lt;/h2&gt;
&lt;p&gt;Tener al menos algunos tests para cada parte del código nos ayudará a mantener los diferentes módulos desacoplados y pueden servir para comprobar al menos las funcionalidades más comunes.&lt;/p&gt;

&lt;h2 id=&quot;tener-un-equipo-de-qa-que-revise-el-código-antes-de-publicarlo-es-mucho-mejor-que-probarlo-tú-mismo&quot;&gt;Tener un equipo de QA que revise el código antes de publicarlo es &lt;strong&gt;mucho mejor que probarlo tú mismo.&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Por mucho que quieras, tú no eres un observador objetivo. Siempre tendrás tendencia a probar el &lt;em&gt;camino feliz&lt;/em&gt;. Además, un buen equipo de QA se puede encargar de escribir tests de integración o test funcionales automáticos. Si tienes la suerte de tener un equipo de QA, escúchalos y aprende de ellos, nadie conoce mejor tu producto.&lt;/p&gt;

&lt;h2 id=&quot;una-tabla-de-pruebas-de-regresión-para-probar-tú-mismo-es-mejor-que-nada&quot;&gt;Una tabla de pruebas de regresión para probar tú mismo es mejor que NADA&lt;/h2&gt;
&lt;p&gt;Entre el abismo y una chuleta el día del examen, al menos está bien tener la chuleta.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Si no tienes una tabla de pruebas funcionales, no tienes tests automáticos y no tienes un equipo de QA, básicamente estás &lt;em&gt;con el culo al aire&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seguramente tú has probado tu producto mientras lo desarrollabas, pero cuando el cliente lo use, fallará de mil formas que no habías pensado y cada vez que tengas que hacer algún cambio lo harás con miedo a no romper nada. Habrá partes del código que no querrás ni tocar porque &lt;em&gt;“si funciona no lo toques”&lt;/em&gt; y poco a poco te preguntarás cómo has creado ese monstruo.&lt;/p&gt;

&lt;p&gt;Las herramientas de test, de cobertura y análisis de código &lt;strong&gt;no te dicen si tu software funciona como debería&lt;/strong&gt;, no entienden de qué va tu aplicación y no pueden avisarte de un fallo en el contenido o en los requisitos. Pero te ayudan a saber cómo funciona el código y por qué, qué casos no has tenido en cuenta en los tests o qué partes del código son más problemáticas.&lt;/p&gt;

&lt;p&gt;Las pruebas de software, son parte del proceso de diseño y desarrollo, porque aseguran que cumplimos las especificaciones y que nuestro diseño es correcto. Y es que…&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;“Without requirements or design , programming is the art of adding bugs to an empty text file.” - Louis Srygley&lt;/p&gt;&amp;mdash; Programming Wisdom (@CodeWisdom) &lt;a href=&quot;https://twitter.com/CodeWisdom/status/912738902376632321&quot;&gt;September 26, 2017&lt;/a&gt;&lt;/blockquote&gt;

</content>
 </entry>
 
 <entry>
   <title>Generadores de código, desarrollo automático y por qué es difícil una IA que programe.</title>
   <link href="http://juanmirod.github.io/2017/09/13/desarrollo-automatico.html"/>
   <updated>2017-09-13T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/09/13/desarrollo-automatico</id>
   <content type="html">&lt;blockquote&gt;
  &lt;p&gt;ACTUALIZACIÓN: Este post tiene unos años, y aunque todo lo que digo en él sigue siendo válido, el campo de la IA ha avanzado mucho en los últimos años. Para más detalles sobre desarrollo asistido con chatgpt y otras herramientas generativas puedes leer mi post sobre &lt;a href=&quot;http://juanmirod.github.io/2023/04/16/trabajando-con-chat-gpt.html&quot;&gt;Desarrollo con ChatGPT&lt;/a&gt; para leer más sobre hacia dónde creo que irá esta tecnología tengo varios artículos sobre la importancia de ChatGPT y de las nuevas &lt;a href=&quot;http://juanmirod.github.io/2024/04/23/ia-y-trabajo.html&quot;&gt;IAs en el trabajo&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Es evidente, que gran parte de lo que hacemos los desarrolladores es suplantarnos a nosotros mismos. O dicho de otra forma, automatizar procesos que podríamos hacer a mano, pero que podemos automatizar, mejorando en velocidad, eficiencia, tolerancia a errores, reproducibilidad, portabilidad, independencia…&lt;/p&gt;

&lt;p&gt;En todos los proyectos hay partes del desarrollo tediosas o repetitivas que solemos automatizar: tests runners, compilación, generadores de clases o componentes, procesos de empaquetado, implantación, etc, etc.&lt;/p&gt;

&lt;p&gt;La pregunta inevitable entonces es:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;¿Hasta donde podemos automatizar?&lt;/strong&gt; &lt;strong&gt;¿Podemos crear un programa que desarrolle programas?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/architect.png&quot; alt=&quot;Fotograma mostrando el Arquitecto de Matrix Revolution&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Como todo desarrollador, en más de una ocasión me he planteado cómo podría crearse un programa que generara gran parte o todo el código que escribo. Muchos dirán que hacer un programa con la capacidad de abstracción como para comprender un problema y crear una solución sería una Inteligencia Artificial General, pero si en lugar de decirlo así, planteas el problema como &lt;strong&gt;traducir una serie de especificaciones a una serie de instrucciones en un lenguage de programación de alto nivel&lt;/strong&gt; El problema empieza a parecer mucho menos abstracto y etéreo y más metódico y concienzudo, que es donde los ordenadores nos ganan &lt;em&gt;de calle&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;En este sentido, hay varios caminos que se han intentado seguir hasta ahora para conseguir acercarse al &lt;em&gt;“programa que programe”&lt;/em&gt; o dicho de otra manera, para depender menos, o nada, de los desarrolladores.&lt;/p&gt;

&lt;p&gt;El extremo son los CMS como Wordpress, Prestashop o Magento. Sistemas completamente funcionales, con los que podemos tener una web dinámica con poco más que apretar un botón, mientras siguen pudiendose extender y modificar mediante código.&lt;/p&gt;

&lt;p&gt;Antes, para crear una web o un blog necesitábamos contratar un servicio de hosting, programar cada una de las páginas y sus interacciones, diseñar y crear la base de datos, etc. Ahora pulsamos un botón y tenemos una nueva instancia de Wordpress y podemos cambiar su apariencia y funcionalidad con unos cuantos clicks de ratón.&lt;/p&gt;

&lt;p&gt;Este blog, por poner otro ejemplo, está alojado en github utilizando Jekyll y Github Pages. Ahora mismo estoy editando un fichero de texto en mi ordenador, pero cuando ejecuto &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push&lt;/code&gt; el texto se sube a github, dispara un proceso que compila el HTML de la página y lo sube a los CDN de github. Solo con un comando, no tengo que preocuparme de servidores, ni bases de datos, ni de programar nada.&lt;/p&gt;

&lt;p&gt;Pero claro, estos sistemas tienen una función concreta, si quieres &lt;em&gt;“otra cosa”&lt;/em&gt;, un producto o servicio software nuevo, tienes que desarrollarlo, y para eso necesitarás un programador.&lt;/p&gt;

&lt;p&gt;Aunque tampoco empezamos sobre un lienzo vacío:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lo más habitual son los frameworks de desarrollo&lt;/strong&gt;. Angular, React, Vue, Laravel, Symfony, Sprint, Play, etc. Son conjuntos de librerías construidas sobre el lenguaje de turno que nos permiten acelerar y dar estructura al desarrollo sin tener que detenernos en muchos detalles de diseño. Estos frameworks establecen patrones y organizan el código de forma que nos ahorran un montón de tiempo y decisiones, permitiéndonos desarrollar aplicaciones más grandes y fiables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cucumber y el desarrollo de tests de comportamiento&lt;/strong&gt; en general son una aproximación a una forma de escribir especificaciones que den más control a los gestores o jefes de producto. En realidad cucumber no automatiza el desarrollo, solo las especificaciones, de forma que son comprobables y reproducibles. Pero no pueden generar el código de la aplicación por si mismas, al menos no hasta ahora.&lt;/p&gt;

&lt;p&gt;Las DSLs o &lt;strong&gt;lenguajes de dominio específico&lt;/strong&gt;, son algo parecido. Se crea un lenguaje de muy alto nivel y centrado en el dominio concreto del negocio, de forma que sea fácil para los expertos no desarrolladores escribir programas en este nuevo lenguaje específico.&lt;/p&gt;

&lt;p&gt;Es más claro y exitoso ejemplo de esto son las hojas de excel. En excel, cada negocio, o incluso cada usuario, crea sus propias reglas, tablas y cálculos, que hacen la función de una DSL. De esta forma se pueden conseguir cálculos complejos sin necesidad de un desarrollador profesional. Excel se usa en muchas profesiones que no consideramos cercanas al desarrollo, pero que utilizan la potencia de un lenguaje de alto nivel, declarativo y multidioma para programar algoritmos casi sin saberlo.&lt;/p&gt;

&lt;p&gt;Las redes neuronales, y en especial &lt;strong&gt;las redes de aprendizaje profundo&lt;/strong&gt;, son otra aproximación a la generación de programas que suplanten sistemas desarrollados a mano. Las redes de aprendizaje profundo están demostrando mejorar los resultados de enormes sistemas expertos o de reglas desarrollados a mano durante años, reduciendo el tiempo de desarrollo enormemente. Hoy en día, clasifican imágenes, emails, posts en redes sociales, reconocen personas e incluso diseñan piezas de ingeniería que usan menos material y son más resistentes. Personalmente tengo mucha confianza en que las redes neuronales solucionarán muchos de los problemas actuales, hay muchos equipos con mucho talento investigando arquitecturas de redes neuronales que resuelven problemas impensables hace unos años, merecen mención especial en este campo DeepMind y &lt;a href=&quot;http://juanmirod.github.io/2016/03/13/Demis-Hassabis-el-hombre-que-nos-dejara-obsoletos.html&quot;&gt;Demis Hassabis, del que hablo un poco en este otro artículo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Otro gran avance que ha conseguido escalar los sistemas a nivel mundial es &lt;strong&gt;“la nube”&lt;/strong&gt;. Los contenedores y los servidores virtuales que nos abstraen del problema de tener un servidor físico en un lugar concreto hacen que no necesitemos una armada de desarrolladores para poder escalar nuestro sistema a nivel mundial.&lt;/p&gt;

&lt;p&gt;Pero todos estos son aplicaciones específicas dentro de dominios específicos. Al final no son más que soluciones (mucho) más complejas, pero parecidas a &lt;em&gt;“automatizar el build”&lt;/em&gt;. No le damos un problema abierto a la máquina y esta nos devuelve un programa que lo resuelve, sino que dentro de un dominio conocido y un rango de parámetros (enorme en algunos casos) la máquina nos devuelve una respuesta, una plantilla, o una estimación.&lt;/p&gt;

&lt;p&gt;Y es que hasta ahora esa es la forma que entendemos que funciona una máquina: le damos un input y nos devuelve un output. Pregunta-respuesta. Pero, hasta ahora al menos, no hemos conseguido crear una máquina que &lt;em&gt;“razone”&lt;/em&gt; en el sentido amplio de la palabra.&lt;/p&gt;

&lt;p&gt;Es de nuevo el problema de la IAG.&lt;/p&gt;

&lt;p&gt;Por ejemplo, El reto del coche autónomo es enorme ya que es el primer robot autoguiado que se mueve en un entorno real con seres humanos (autopilotar un barco o un avión &lt;em&gt;parece&lt;/em&gt; un juego de niños en comparación) La cantidad de trabajo necesario para conseguir que los diferentes sistemas funcionen juntos y de acuerdo a toda una serie de normas escritas y no escritas para que un coche autónomo ceda el paso al incorporarse a una rotonda es enorme. Necesitamos un modelo muy detallado que requiere mucho conocimiento tanto del mundo real (los otros coches, la carretera, el tiempo), como de las reglas que queremos que cumpla el robot, como del propio funcionamiento del robot (¿Cuando acelera el coche? ¿Cuánto peso está cargando? ¿Tengo tiempo de incorporarme al carril que quiero? lo que se llama &lt;em&gt;introspección&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Pero aun así, una cosa es enseñar a un robot a conducir un coche, de acuerdo a una serie de lecturas de sus sensores y una serie de reglas y el conocimiento del &lt;em&gt;hardware&lt;/em&gt;, y otra diferente, es tratar de hacer un programa que comprenda por qué necesitamos coches autónomos, cómo deben ser y que sea capaz de diseñarlos y/o codificarlos. El número de variables y decisiones en el segundo problema es muchísimo mayor. O dicho de otra forma, mucha gente puede conducir un coche, pero solo un equipo de expertos ingenieros, diseñadores y desarrolladores puede producir un conche autónomo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/jarvis.gif&quot; alt=&quot;Escena del asistente virtual de Ironman: JARVIS&quot; /&gt;&lt;/p&gt;

&lt;p&gt;El problema, no sólo de un coche autónomo se mueve por el mundo, sino de cualquier sistema complejo, es que debe tener en cuenta un millar de factores diferentes. El mundo real, el propio hardware y software sobre el que funciona y con el que se produce… hay cientos de detalles que aun no hemos conseguido abstraer, el trabajo de desarrollador tiene mucho de tender puentes para que unas librerías funcionen con otras.&lt;/p&gt;

&lt;p&gt;Al final, cualquier especificación lo suficientemente detallada como para generar un programa ejecutable, tiene que bajar al nivel del código. Y esto es así porque tiene que contener cientos, si no miles o decenas de miles, de condiciones, instrucciones y casos específicos que responden a exigencias concretas del cliente, el entorno y las librerías y APIs con las que interacciona el sistema a especificar.&lt;/p&gt;

&lt;p&gt;Cuando trato de explicar esto a alguien siempre be acuerdo del &lt;a href=&quot;https://www.youtube.com/watch?v=qHqDpUpbpJI&quot;&gt;sketch de Tip y Col sobre cómo llenar un vaso de agua.&lt;/a&gt; y es que, hasta en el gesto más sencillo, hay mil presunciones y mil formas en las que podríamos hacerlo mal.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://media.giphy.com/media/Bqn8Z7xdPCFy0/giphy.gif&quot; alt=&quot;Gif of a cartoon character trying to drink water by the wrong way of the glass&quot; /&gt;&lt;/p&gt;

&lt;p&gt;En este sentido, hay un proyecto muy interesante en muchos aspectos, el Cyc, es el proyecto de inteligencia artifical más lonjevo hasta ahora, y uno de los pocos que trata de codificar el conocimiento no escrito, cosas como las del sketch de Tip y Col, que no están escritas, cosas como que si ves a alguien con el pelo verde, debe habérselo teñido porque los humanos no tenemos el pelo verde de forma natural. Para saber más sobre Cyc puedes leer &lt;a href=&quot;https://www.wired.com/2016/03/doug-lenat-artificial-intelligence-common-sense-engine/&quot;&gt;este artículo wn wired&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En resumen, podemos automatizar tareas concretas, cada vez más y más amplias o que abarcan más capacidades que hasta ahora considerábamos humanas, como identificar una voz o un rostro, etiquetar una fotografía con conceptos u objetos que aparecen en ella, conducir un coche o crear un diseño de acuerdo a unas normas. Pero aún nos queda mucho camino para automatizar totalmente el trabajo de los desarrolladores. Poco a poco vamos poniendo nuevas capas de abstracción sobre las anteriores, para conseguir cada vez abarcar más con menos. Pero la clave está en que &lt;strong&gt;siempre, sobre la última capa, puedes poner desarrolladores a ampliar y conectar funcionalidades de formas nuevas y resolver problemas que antes no estaban a tu alcance. Y eso, por ahora, solo lo puede hacer un ser humano.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resolver un problema complejo extrapolando a partir de tus conocimientos require de una capacidad de raciocinio que, solo tenemos nosotros.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;En la actualidad, las distintas formas de generación de código nos sirven para llegar cada vez más lejos. Cuantas más herramientas y más capas ponemos sobre nuestros lenguajes, mayores son los retos que podemos afrontar. Creamos programas que crean programas, que a su vez son los nuevos bloques que usaremos para construir más grande y mejor. Pero todos sabemos que el crecimiento infinito es imposible y nuestro intelecto limitado.&lt;/p&gt;

&lt;p&gt;¿Llegará el día en el que no podamos abstraer por encima de lo que ya tenemos? ¿Llegará el día en el que un programa sea capaz de encontrar una solución a un problema al mismo nivel o mejor que un ser humano? Personalmente estoy bastante convencido de que ese día llegará, lo que no sé es lo que pasará después.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Generadores en JavaScript</title>
   <link href="http://juanmirod.github.io/2017/09/11/Generadores-JavaScript.html"/>
   <updated>2017-09-11T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/09/11/Generadores-JavaScript</id>
   <content type="html">&lt;p&gt;Los generadores son una herramienta de programación muy poderosa, pero difícil de entender cuando la vemos por primera vez. En este artículo trataré de definir de forma lo más sencilla posible qué son y como se usan los generadores y pasar a varios ejemplos prácticos en los que los generadores nos permiten simplificar código o directamente hacer cosas que no pensábamos que se pudieran hacer en JavaScript como funciones de evaluación perezosa y corutinas.&lt;/p&gt;

&lt;h3 id=&quot;qué-es-un-generador&quot;&gt;¿Qué es un generador?&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/1024px-Modern_Steam_Turbine_Generator.jpg&quot; alt=&quot;Imagen de un generador en una planta eléctrica&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Un generador es una función especial en JavaScript que puede pausar su ejecución y retomarla en un punto arbitrario. Para definirlos utilizamos dos nuevas palabras reservadas del lenguaje: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;function*&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Este es uno de los casos más claros en los que he encontrado que la barrera del idioma a veces dificulta la comprensión de ciertos conceptos. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; es una palabra poco habitual en inglés, y para un no-nativo como yo, me suena totalmente fuera de contexto. Se traduce como &lt;em&gt;producir&lt;/em&gt; o &lt;em&gt;ceder&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Trataré de explicar su funcionamiento con un ejemplo de código:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counterGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counterGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// { value: 0, done: false }&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// { value: 1, done: false }&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// { value: 2, done: false }&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// hasta el infinito y más allá!&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este sencillo ejemplo muestra el funcionamiento de un generador. El uso más habitual de los generadores es &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators&quot;&gt;crear &lt;em&gt;Iteradores&lt;/em&gt;&lt;/a&gt;. Un &lt;em&gt;Iterador&lt;/em&gt; es un objeto que devuelve un elemento de una colección cada vez que llamamos a su método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.next&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;counterGenerator&lt;/code&gt; devuelve un iterador que asignamos a la variable counter.&lt;/p&gt;

&lt;p&gt;Los generadores siempre devuelven un iterador y en el momento en el que llamamos al método &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.next&lt;/code&gt; del iterador, éste ejecuta la función del generador hasta llegar al primer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; que encuentra, que detiene la ejecución de la función y &lt;em&gt;produce&lt;/em&gt; un resultado, o dicho de otra forma, produce un elemento de la colección.&lt;/p&gt;

&lt;p&gt;El resultado es siempre un objeto con dos propiedades, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;done&lt;/code&gt;, en la primera está el valor producido por &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; y la segunda es para indicar si el iterador ha terminado, es decir, si ese era el último elemento de la colección.&lt;/p&gt;

&lt;p&gt;En la siguiente llamada a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.next&lt;/code&gt; la función continúa desde el &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; y hasta el siguiente &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt;, y así hasta encontrar un &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt; que devolverá &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; como valor de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;done&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;El iterador devuelto por &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;counterGenerator&lt;/code&gt; Puede usarse a su vez dentro de un bucle &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for of&lt;/code&gt;, ya que estos bucles utilizan el interface del iterador para obtener el valor de cada iteración:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// break detiene el bucle for como si hubiera encontrado done === true&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 3&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 10&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;bucles-infinitos-y-evaluación-perezosa&quot;&gt;Bucles infinitos y evaluación perezosa&lt;/h3&gt;

&lt;p&gt;En el ejemplo anterior hemos usado todo el tiempo un bucle &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;while (true)&lt;/code&gt; sin bloquear o saturar la cpu y sin ninguna alerta por parte de node. Esto es así porque &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; pausa la 
ejecución de la función, y por lo tanto, pausa el bucle infinito, cada vez que produce un valor.&lt;/p&gt;

&lt;p&gt;Esto es lo que se llama &lt;em&gt;evaluación perezosa&lt;/em&gt; y es un concepto importante en lenguajes funcionales como Haskell. Básicamente nos permite tener listas o estructuras de datos &lt;em&gt;“infinitas”&lt;/em&gt; y operar sobre ellas, por ejemplo podemos tener un operador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;take(n)&lt;/code&gt; que toma los N primeros elementos de una lista infinita:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oddsGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oddNumbers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oddsGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// TODOS los números impares &lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oddNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// toma 5 números impares&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 3&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 5&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 7&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 9&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;La evaluación perezosa permite construir este tipo de estructuras &lt;em&gt;“infinitas”&lt;/em&gt; o completas sin producir errores de ejecución y también son más eficientes en algoritmos de búsqueda, recorrido de árboles y cosas así, al evaluar el mínimo número de nodos necesarios para encontrar la solución. Para ver más usos y ventajas de la evaluación perezosa puedes ver &lt;a href=&quot;https://stackoverflow.com/questions/265392/why-is-lazy-evaluation-useful&quot;&gt;este hilo de stackoverflow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como añadido en JavaScript, los generadores nos permiten crear una sintaxis más legible en el uso de arrays. Podemos obtener los valores producidos por el generador en ES6 mediante el &lt;em&gt;spread operator&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;limit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ 0, 1, 2, 3, 4 ] &lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pero cuidado con utilizar el &lt;em&gt;spread operator&lt;/em&gt; o los bucles for con listas infinitas como la de arriba:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oddNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// bucle infinito!!&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;oddNumbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// bucle infinito y &apos;out of memory&apos;, no podemos crear un array infinito en la memoria!!&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;asyncawait-y-corutinas&quot;&gt;Async/await y corutinas&lt;/h3&gt;

&lt;p&gt;Además de la generación de iteradores, los generadores nos permiten controlar la ejecución de funciones asíncronas gracias al mecanismo de pausa de la función de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt;. Para explicar por qué esto es importante, vamos a desviarnos un momento y hablar de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Una de las funcionalidades más coreadas de ES7 son las nuevas construcciones &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;, que nos permiten ejecutar código asíncrono pero escribiéndolo de forma lineal, sin necesidad de pensar en callbacks o promesas. Veamos cómo funciona:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;helloDelayed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;greeting&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;helloDelayed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;greeting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// a los 5 segundos aparece &apos;Hello&apos;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lo genial de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; es que el código de la función async es lineal, le hemos pasado una promesa a await y nos devuelde directamente el valor con el que se ha resuelto, esperando y deteniendo la ejecución de la función.&lt;/p&gt;

&lt;p&gt;No me voy a detener más en explicar cómo funciona, eso lo dejo para otro post, pero &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; en realidad no es más que un uso concreto de los generadores, &lt;em&gt;azúcar sintáctico&lt;/em&gt; para usar un generador y evaluar una promesa, podríamos replicar esta funcionalidad, para una sola llamada (más adelante veremos la generalización) así:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;helloDelayed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iterator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;helloDelayed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;iterator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;greeting&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;greeting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Esta solución es más difícil de leer y de escribir, sobre todo por el doble &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.next&lt;/code&gt; necesario para que funcione, y por la poca legibilidad del comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; en si mismo. Pero muestra una parte importante del funcionamiento de los generadores.&lt;/p&gt;

&lt;p&gt;Lo que está pasando aquí es que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hi&lt;/code&gt; recibe un generador como parámetro, lo ejecuta y llama una vez a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.next&lt;/code&gt; para ejecutar el generador hasta el yield y luego lo vuelve a llamar cuando tiene el resultado de la promesa para revolver el resultado al yield.&lt;/p&gt;

&lt;p&gt;Hasta ahora no habíamos hablado de esto para no complicar más, pero podemos añadir a la llamada a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.next&lt;/code&gt; un parámetro, que a su vez podemos capturar en una variable asignándola a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt;. Esta, para mi, es la funcionalidad más confusa de los generadores, pero es la clave para usarlos para ejecutar llamadas asíncronas o corutinas como veremos en los siguientes ejemplos. Veamos un pequeño ejemplo de como funciona:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counterGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;counterGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;c1&quot;&gt;// { value: 0, done: false }&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// el primer &apos;next&apos; no imprime nada porque el generador se ejecuta solo hasta el yield&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ho&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;c1&quot;&gt;// ho&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// { value: 1, done: false }&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;hu&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;c1&quot;&gt;// hu&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// { value: 2, done: false }&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este mecanismo nos da una forma de comunicarnos con el generador, algo muy potente, aunque en mi opinión con una sintaxis difícil de leer y nada clara. Los generadores no son una herramienta que hay que usar con moderación, pero nos permiten hacer cosas que estarían fuera del alzance de JavaScript si no fuera con ellos, como el ejemplo que veremos a continuación.&lt;/p&gt;

&lt;p&gt;Generalizando el código de helloDelayed, se puede construir una función que controle la ejecución de funciones asíncronas prácticamente igual a como hace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt;, veamos un ejemplo que lee dos ficheros (ejemplo tomado de &lt;a href=&quot;https://medium.com/@tjholowaychuk/callbacks-vs-coroutines-174f1fe66127&quot;&gt;este post de TJ HoloWaychuck&lt;/a&gt;, que recomiendo leer, el código original usa callbacks, pero lo he modificado para usar promesas, dos ejemplos por el precio de uno &lt;em&gt;;)&lt;/em&gt;):&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  
  &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;README.md&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;index.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;


&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este código, sí se parece mucho más al de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt;, es más, si cambiamos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thread&lt;/code&gt; por &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; y imaginamos que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; es &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; es prácticamente igual:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;README.md&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;index.html&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este ejemplo básico es una simplificación de la librería &lt;a href=&quot;https://github.com/tj/co&quot;&gt;Co&lt;/a&gt;, que nos permite escribir este tipo de código asíncrono de forma lineal y con la seguridad de que captura todas las excepciones de forma parecida a como hacen las Promesas.&lt;/p&gt;

&lt;p&gt;Técnicamente esto no son corutinas. En realidad, cuando hablamos de generadores, hablamos de &lt;a href=&quot;https://en.wikipedia.org/wiki/Coroutine#Comparison_with_generators&quot;&gt;&lt;em&gt;‘semicorutinas’&lt;/em&gt;&lt;/a&gt; porque los generadores no son tan flexibles como las corutinas de lenguajes como Go, pero diremos que son equivalentes a corutinas, aún sabiendo que estamos simplificando, porque es la herramienta que tenemos para esta función en JavaScript a nivel nativo.&lt;/p&gt;

&lt;p&gt;En cuando a otras librerías para corutinas, &lt;a href=&quot;https://github.com/fibjs/fibjs&quot;&gt;fibjs&lt;/a&gt; y &lt;a href=&quot;https://github.com/laverdet/node-fibers&quot;&gt;node-fibers&lt;/a&gt; son implementaciones de &lt;em&gt;‘fibers’&lt;/em&gt; que podríamos traducir como &lt;em&gt;“fibras”&lt;/em&gt; o &lt;em&gt;“hilos ligeros”&lt;/em&gt; que es más flexible que los generadores y que algunos desarrolladores &lt;a href=&quot;https://github.com/nodejs/node/issues/9131&quot;&gt;quieren incluir en el núcleo de Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Los generadores y las corutinas son herramientas avanzadas del lenguaje que seguramente no tengas que utilizar directamente a no ser que hagas desarrollo de sistemas o librerías, pero de las que podemos sacar provecho en nuestro código con librerías como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Co&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-fibers&lt;/code&gt; o el nuevo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; nativo. Espero que estos ejemplos hayan resuelto algunas dudas y generado aun más dudas e interés por el lenguaje y sirva como introducción a todo este tema.&lt;/p&gt;

&lt;p&gt;Otra lectura recomendada para profundizar en los Generadores es el libro de Kyle Simpson ES6 and Beyond, y en concreto &lt;a href=&quot;https://github.com/getify/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/ch3.md#generators&quot;&gt;el capítulo sobre Iteradores y Generadores&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Soluciones exámenes ética y legislación UNED</title>
   <link href="http://juanmirod.github.io/2017/08/16/etica-y-legislacion.html"/>
   <updated>2017-08-16T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/08/16/etica-y-legislacion</id>
   <content type="html">&lt;p&gt;Soluciones a los exámenes de Ética y Legislación de la UNED entre 2015 y 2017. &lt;strong&gt;Estas soluciones no están comprobadas ni verificadas por ningún profesor&lt;/strong&gt;. Las respuestas son el resultado de leer el texto de referencia &lt;a href=&quot;https://www.librosuned.com/LU14262/Derecho-e-inform%C3%83%C2%A1tica-%C3%83%C2%A9tica-y-legislaci%C3%83%C2%B3n.aspx&quot;&gt;Derecho e Informática&lt;/a&gt; y tratar de sintetizar una respuesta para cada pregunta. Para una información más precisa y detallada es mejor leer el libro original. Simplemente estoy estudiando la asignatura y pensé que podría compartir mi trabajo por si a alguien le sirve en el futuro.&lt;/p&gt;

&lt;p&gt;Hay algunos temas de la asignatura, sobre todo los referentes a derechos de autor y delitos informáticos, que me parecen muy interesantes y trataré de ampliar en un futuro en un lenguaje más llano, ya que entiendo que estos resúmenes no son útiles si no es para estudiar la asignatura por ser demasiado específicos y carecer de contexto.&lt;/p&gt;

&lt;p&gt;Si quieres contribuir con más respuestas a exámenes o correcciones sobre el texto puedes hacerlo &lt;a href=&quot;https://github.com/juanmirod/juanmirod.github.io/blob/master/_posts/2017-08-16-etica-y-legislacion.markdown&quot;&gt;aquí&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;examen-primera-semana-de-julio-de-2017&quot;&gt;Examen Primera semana de Julio de 2017&lt;/h1&gt;

&lt;h2 id=&quot;1-el-uso-de-la-informática-como-factor-de-estandarización-tema-1-pag-51&quot;&gt;1. El uso de la informática como factor de estandarización. (Tema 1 pag. 51)&lt;/h2&gt;

&lt;p&gt;Es uno de los problemas objetivamente vinculados a la relación contractual. El recurso a los contratos estándard es habitual en la contratación desde Internet a través de páginas web en forma de una serie de clausulas o condiciones generales que el consumidor es llamado a aceptar para la conclusión del contrato. Es fundamental analizar el modo en el que se recogen las cláusulas del contrato que el consumidor debe aceptar aunque este aspecto también es relevante en la contratación entre profesionales.&lt;/p&gt;

&lt;h2 id=&quot;2-momento-de-nacimiento-del-contrato-en-internet-tema-5-pag-210&quot;&gt;2. Momento de nacimiento del contrato en Internet. (Tema 5 pag. 210)&lt;/h2&gt;

&lt;p&gt;Cuando las partes se encuentran no presentes - ni físicamente ni mediante un medio de comunicación simultánea - se entiende que el destinatario tiene acceso al contenido del mensaje que recoje la aceptación cuando alcanza su dirección electrónica. Es decir, si el contrato se realiza mediante intercambio de mensajes por correo electrónico, desde el momento en el que el mensaje alcanza su dirección de correo electrónico. Solo pudiendo aceptarse como causa de exoneración un fallo en el proveedor de correo electrónico que impida el acceso a éste.&lt;/p&gt;

&lt;p&gt;Si el contrato es concluido a través de una página web, se entenderá que la orden o aceptación contractual es efectuada desde el momento en el que el programa informático de contratación recibe el correspondiente “clicado”, “aceptación” o “compra” definitivo del destinatario y el proveedor de servicios puede acceder a él.&lt;/p&gt;

&lt;p&gt;Sobre este tema es referencia obligada el artículo 15 de la Ley Modelo de la CNUDMI sobre comercio electrónico: Tiempo y lugar del envío y la recepción de un mensaje de datos.&lt;/p&gt;

&lt;h2 id=&quot;3-las-comunicaciones-comerciales-su-regulación-y-su-posible-repercusión-en-el-contrato-tema-6-pag-223&quot;&gt;3. Las comunicaciones comerciales: su regulación y su posible repercusión en el contrato (Tema 6 pag 223)&lt;/h2&gt;

&lt;p&gt;Comunicaciones comerciales:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“son todas las formas de comunicación destinadas a promocionar directa o indirectamente bienes, servicios o la imagen de una empresa, organización o persona con una actividad comercial, industrial, artesanal o de profesiones reguladas”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No se consideran comunicaciones comerciales:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“los datos que permiten acceder directamente a la actividad de dicha empresa, organización o persona y, concretamente el nombre de dominio o la dirección de correo electrónico […] y las comunicaciones relativas a los bienes, servicios o a la imagen de dicha empresa, elaboradas de forma independiente de ella, en particular cuando estos se realizan sin contrapartida económica.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Conclusión: conjunto de actividades variadas que el prestador de servicios –profesional- realiza durante la
fase precontractual de cualquier hipotético futuro contrato con el fin de alcanzar su conclusión: publicidad,
descuentos, premios, regalos, ofertas, concursos, invitaciones,…&lt;/p&gt;

&lt;p&gt;La Directiva 2000/31/CE exige que deban ser identificables como tales, y en nombre de quien se realizan. El
envío indiscriminado de comunicaciones comerciales a destinatarios que no las hayan solicitado puede
conllevar responsabilidades a la persona en nombre de la que se envían. Las ofertas promocionales (descuentos, premios, regalos, concursos o juegos) Cuando estén permitidas por el Estado miembro del establecimiento, deberán ser claramente identificables, además de ser accesibles, inequívocas y claras las condiciones para acceder a ellas.&lt;/p&gt;

&lt;p&gt;Según el artículo 13 de la Directiva 2002/58/CE las comunicaciones comerciales no solicitadas no están permitidas, con lo que se requiere que hayan sido consentidas por el destinatario, salvo cuando el prestador de servicio envíe las comunicaciones con posterioridad a una relación contractual (en la cual el cliente haya proporcionado la dirección de correo electrónico) siempre en relación a productos similares y con la posibilidad de rechazar futuras comunicaciones.&lt;/p&gt;

&lt;p&gt;La ley española distingue 3 tipos de comunicaciones comerciales: las de estricta naturaleza publicitaria –a las
que exige que figure al inicio del mensaje la expresión “publicidad”-, las ofertas promocionales – que incluyen
descuentos, premios y regalos-, y los concursos o juegos promocionales.&lt;/p&gt;

&lt;p&gt;En todo caso queda prohibido el envío de comunicaciones comerciales en las que se disimule o se oculte la
identidad del remitente, así como las que inciten a visitar páginas que contravengan lo dispuesto.&lt;/p&gt;

&lt;p&gt;El destinatario podrá revocar en cualquier momento su consentimiento a recibir comunicaciones comerciales
con la simple notificación de su voluntad mediante procedimientos simples y gratuitos.&lt;/p&gt;

&lt;p&gt;Se consideran &lt;strong&gt;“infracciones graves”&lt;/strong&gt; (30001 - 150000 €):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;El envío masivo de comunicaciones comerciales por e-mail u otro medio electrónico, o el envío, en el
plazo de un año, de más de 3 a un mismo destinatario, si no se cumplen los requisitos.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;El incumplimiento de la obligación de incorporar procedimientos para revocar el consentimiento
prestado.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;4-protección-de-los-programas-de-ordenador-en-el-derecho-español-contenido-de-los-derechos-de-explotación-tema-9---pag-308&quot;&gt;4. Protección de los programas de ordenador en el Derecho español: contenido de los derechos de explotación (Tema 9 - pag. 308)&lt;/h2&gt;

&lt;p&gt;Se exige permiso del autor para el uso del software, incluso cuando se trate de reproducción para uso personal. Esta autorización se materializa en las Licencias de Uso, que indican los derechos y restricciones al consumidor, según la licencia.&lt;/p&gt;

&lt;p&gt;Solo el titular de los derechos está facultado para autorizar o prohibir la traducción o adaptación del programa de ordenador a otro lenguaje de programación, así como la realización de cualquier proceso que provoque una alteración sustancial del resultado logrado por el programador originario.&lt;/p&gt;

&lt;p&gt;La distribución de un programa informático abarca la puesta en circulación o comercialización del original o copia en un soporte tangible, mediante venta, alquiler, o cualquier otro acto de disposición.&lt;/p&gt;

&lt;h1 id=&quot;examen-segunda-semana-de-julio-de-2017&quot;&gt;Examen Segunda semana de Julio de 2017&lt;/h1&gt;

&lt;h2 id=&quot;1-definición-de-comercio-electrónico-tema-2-pags-80-84&quot;&gt;1. Definición de comercio electrónico (Tema 2 pags 80-84)&lt;/h2&gt;

&lt;p&gt;El término comercio electrónico aún no tiene una definición formal concreta y al tratar de describirlo se usan términos ambiguos que acaban abarcando a lo que se se puede entender por &lt;strong&gt;“sociedad de la información”&lt;/strong&gt;. En la comunicación &lt;strong&gt;“una iniciativa europea en materia de comercio electrónico”&lt;/strong&gt; COM (97) 157, se recogen algunos puntos claves sobre para una definición más acotada:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Consiste en la práctica de actividades comerciales mediante el procesamiento y/o la transmisión electrónica de datos.&lt;/li&gt;
  &lt;li&gt;No es un fenómeno nuevo que se inicia con la aparición de Internet. Ya se realizaba antes en redes cerradas (ECI).&lt;/li&gt;
  &lt;li&gt;Comprende actividades comerciales con comunicación directa y a distancia y también actividades en las que no hay comunicación directa.&lt;/li&gt;
  &lt;li&gt;Podrá ser directo o indirecto, según si todo el proceso (solicitud, pago y entrega) es exclusivamente electrónico o no.&lt;/li&gt;
  &lt;li&gt;Internet ha aportado al CE un mayor desarrollo, así como una generalización y ampliación de los sujetos que lo practican.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-contratos-celebrados-a-través-de-una-subasta-electrónica-tema-3-pags-133-134&quot;&gt;2. Contratos celebrados a través de una subasta electrónica (Tema 3 pags 133-134)&lt;/h2&gt;

&lt;p&gt;El procedimiento de subasta electrónica combina elementos de la contratación mediante página web y la contratación por correo electrónico. Está compuesto por:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;El esquema contractual de la subasta
    &lt;ul&gt;
      &lt;li&gt;Suelen consistir exclusivamente en compraventa, a menudo excluyendo determinados objetos como animales vivos, tabaco, etc.&lt;/li&gt;
      &lt;li&gt;El sujeto titular del bien recibe el nombre de “vendedor” el programa informático realiza el papel del subastador y el conjunto de sujetos interesados son los licitadores o postores.&lt;/li&gt;
      &lt;li&gt;Los objetos que son subastados vienen recogidos en una página web previa con sus características.&lt;/li&gt;
      &lt;li&gt;Para participar en la licitación es necesario registrarse en el servidor y dar datos personales. Paso fundamental para realizar la calificación de vendedor y postores usada para prevenir actuaciones fraudulentas.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;El programa informático de subasta del prestador de servicio
    &lt;ul&gt;
      &lt;li&gt;Desarrolla materialmente la licitación&lt;/li&gt;
      &lt;li&gt;Recoge de forma clara y sencilla las instrucciones técnicas y pasos a seguir por los participantes en la subasta.&lt;/li&gt;
      &lt;li&gt;Realiza la función de director de la licitación.&lt;/li&gt;
      &lt;li&gt;Su funcionamiento es semejante al de una página web para conclusión de contratos, pero con varios sujetos realizando pujas hasta el fin de la subasta.&lt;/li&gt;
      &lt;li&gt;La subasta finaliza cuando se ha cumplido el plazo establecido sin ninguna puja, o porque un postor ha realizado la puja más alta, en cuyo caso queda concluida la compraventa, vinculando al vendedor y al mejor postor, ahora comprador.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;La comunicación a través de correo electrónico
  Se realiza tanto entre el servidor y las partes como entre vendedor y comprador una vez finalizada la puja. Esta es de especial relevancia ya que de ella depende la correcta ejecución del contrato, mediante el envío de la forma de pago y la forma y dirección de envío del objeto.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;3-lugar-de-nacimiento-del-contrato-en-internet-tema-5&quot;&gt;3. Lugar de nacimiento del contrato en internet (Tema 5)&lt;/h2&gt;

&lt;p&gt;El ordenamiento español situa el lugar de nacimiento del contrato en el lugar donde se hizo la oferta, el contrato se considera concluido desde el momento en el que el ofertante tiene conocimiento de la aceptación del contrato aplicando la “buena fé” (teoría del conocimiento + teoría de la recepción).&lt;/p&gt;

&lt;p&gt;En la práctica:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Si las partes están físicamente presentes se considera perfeccionado desde el momento en el que se tiene conocimiento de la aceptación. El lugar de la oferta coincide con el de la perfección.&lt;/li&gt;
  &lt;li&gt;Si la oferta se hizo previamente y las partes se encuentran después el caso es el mismo solo que el lugar de nacimiento es el lugar donde se realizó la oferta.&lt;/li&gt;
  &lt;li&gt;Si las partes están temporal, pero no geográficamente presentes, el momento es el momento en el que se conoce la aceptación, el lugar de nacimiento del contrato será el lugar donde se realizó la oferta, que no tiene por qué coincidir con el de aceptación del contrato (móvil, oferta previa en el tiempo a aceptación)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;4-delitos-contra-la-propiedad-intelectual-tema-10-pag-329&quot;&gt;4. &lt;a name=&quot;delitosPI&quot;&gt;&lt;/a&gt;Delitos contra la propiedad intelectual (Tema 10 pag 329)&lt;/h2&gt;

&lt;p&gt;Con carácter general, el Derecho penal español protege la propiedad intelectual (PI) al sancionar a quien&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;“con ánimo de lucro y en perjuicio de tercero reproduzca, plagie, distribuya o comunique todo o en parte, una obra literaria, artística, científica, o su trasformación, interpretación o ejecución artística fijada en cualquier tipo de soporte o comunicada a través de cualquier medio, sin la autorización de los titulares de los correspondientes derechos de la propiedad intelectual o de sus cesionarios.”&lt;/em&gt; (art 270.1 CP)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;El Derecho español también considera los programas de ordenador como creaciones susceptibles de ser protegidos por el derecho de PI. Son objeto de protección penal tanto el &lt;em&gt;“programa fuente”&lt;/em&gt; como el &lt;em&gt;“programa objeto”&lt;/em&gt;, la documentación preparatoria, la documentación técnica y los manuales de uso, así como las versiones sucesivas del programa y los programas derivados. Quedan excluidas las ideas y principios básicos y aquellos programas creados con el fin de ocasionar efectos nocivos a un sistema informático.&lt;/p&gt;

&lt;p&gt;La regulación del artículo 270.3 CP amplía esta protección, castigando la fabricación, importación, puesta en circulación o posesión de &lt;strong&gt;“cualquier medio específicamente destinado a facilitar la supresión no autorizada o la neutralización  de cualquier dispositivo técnico que se haya utilizado para proteger programas de ordenador”&lt;/strong&gt; No pudiendo aplicarse a programas que además de para este fin, tengan otras utilidades, como la compresión o descompresión o tratado de formatos especiales.&lt;/p&gt;

&lt;p&gt;Cuando existe condena por delito contra la PI, se podrá decretar la publicación de la sentencia, a costa del infrator, en un periódico oficial (BOE, BOCAM…).&lt;/p&gt;

&lt;h1 id=&quot;primera-semana-julio-2016&quot;&gt;Primera semana Julio 2016&lt;/h1&gt;

&lt;h2 id=&quot;1-el-fomento-institucional-del-uso-de-internet-la-discutida-necesidad-de-una-regulación-especial-tema-1&quot;&gt;1. &lt;a name=&quot;discutida&quot;&gt;&lt;/a&gt;El fomento institucional del uso de internet: la discutida necesidad de una regulación especial (Tema 1)&lt;/h2&gt;

&lt;p&gt;El derecho contractual sobre los contratos realizados a través de internet no debe serun cuerpo diferente al precedente derecho contractual, pero sí hay que tener en cuenta las características específicas del medio técnico empleado, esto es, el caracter interactivo, la desmaterialización e internacionalización, etc. Para ello se proponen dos vertientes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;La regulación desde el órgano legislativo nacional o supra-nacional.&lt;/li&gt;
  &lt;li&gt;La autoregulación, o creación de contratos que tenga en cuenta estas características especiales en cada caso. Esto se puede dar en dos modalidades:
    &lt;ul&gt;
      &lt;li&gt;Los pactos de las partes por los cuales determinan el derecho aplicable al contrato&lt;/li&gt;
      &lt;li&gt;Los determinados Códigos de conducta por los que el profesional se compromete unilateralmente a conceder determinadas prerrogativas.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La UE, mediante la Directiva 2000/31/CE opta por la regulación de las características especiales del contrato en internet ya que, dado el carácter internacional inherente a éste, la autoregulación llevaría a un núcleo jurídico difuminado. Aunque la autoregulación puede seguir llevándose a cabo como un añadido a esta regulación básica de la UE.&lt;/p&gt;

&lt;h2 id=&quot;2-el-documento-de-identidad-electrónico-regulación-características-y-utilidad-tema-4-pag-167&quot;&gt;2. &lt;a name=&quot;DNIE&quot;&gt;&lt;/a&gt;El documento de identidad electrónico: regulación, características y utilidad (Tema 4 pag 167)&lt;/h2&gt;

&lt;p&gt;Se define con las funciones que debe cumplir en la Ley 59/2003 de firma electrónica: &lt;em&gt;“el DNI que acredita electrónicamente la identidad personal de su titular y permite la firma electrónica de documentos.”&lt;/em&gt; y también dispone que &lt;em&gt;“todas las personas físicas o jurídicas, públicas o privadas, reconocerán la eficacia del DNO electrónico para acreditar la identidad y los demás datos personales del titular que consten en el mismo, y para acreditar la identidad del firmante y la integridad de los documentos firmados con los dispositivos de firma electrónica en él incluidos”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;De ello se entiende que la la firma electrónica debe ser avanzada y reconocida, permitiendo en un contrato electrónico identificar a las partes y garantizar la integridad del contenido del documento informático en el que se recoge la oferta y/o aceptación contractual. Aunque no resuelve directamente los problemas asociados al pago mediante tarjeta bancaria.&lt;/p&gt;

&lt;p&gt;Su utilidad puede verse en:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Tener acceso a determinadas informaciones recogidas en webs.&lt;/li&gt;
  &lt;li&gt;Conclusión de contratos via internet&lt;/li&gt;
  &lt;li&gt;Relaciones de los administrados con las administraciones públicas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En cuanto a características necesarias:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Reconocido en el mayor ámbito territorial posible, por el momento la UE.&lt;/li&gt;
  &lt;li&gt;De caracter público (en España estaría vinculado al Ministerior de Ciencia y Tecnología y/o al Ministerio de Interior)&lt;/li&gt;
  &lt;li&gt;Gratuito o de cuantía no excesivamente gravosa para el partícular.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Su funcionamiento se asienta en el uso de dos claves asimétricas, la pública, alojada en un registro del ministerio que corresponda y la privada, sólo conocida por el firmante, que le permitirá concluir contratos con ella de forma que el prestador de servicio pueda verificar el firmante mediante la clave pública.&lt;/p&gt;

&lt;h2 id=&quot;3-la-prueba-de-los-contratos-concluidos-en-internet-con-firma-electrónica-la-transposición-en-españa-de-la-directiva-sobre-firma-electrónica-tema-6-pag-249&quot;&gt;3. &lt;a name=&quot;firmaElectronicaEs&quot;&gt;&lt;/a&gt;La prueba de los contratos concluidos en internet con firma electrónica: La transposición en España de la Directiva sobre firma electrónica (Tema 6 pag 249)&lt;/h2&gt;

&lt;p&gt;Tanto la Ley española como la Directiva comunitaria parten de la distinción de dos modelos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;La firma electrónica simple, o genérica: &lt;em&gt;“conjunto de datos en forma electrónica, consignados junto a otros o asociados con ellos, que puede ser utilizados como medio de identificación del firmante”&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;La firma electrónica avanzada: &lt;em&gt;“firma electrónica que permite identificar al firmante y detectar cualquier cambio ulterior en los datos firmados, que está vinculada al firmante de manera única y a los datos a que se refiere y que ha sido creada por medios que el firmante puede mantener bajo su exclusivo control.”&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La primera no tiene la misma validez que la firma manuscrita, pero la segunda sí, siempre que esté basada en un certificado reconocido y haya sido producida por un dispositivo seguro de creación de firma (firma avanzada y reconocida)&lt;/p&gt;

&lt;h2 id=&quot;4-la-protección-de-los-programas-de-ordenador-en-el-derecho-español-límites-a-los-derechos-de-explotación-tema-9-pag-309&quot;&gt;4. &lt;a name=&quot;limitesExplotacion&quot;&gt;&lt;/a&gt;La protección de los programas de ordenador en el Derecho español: Límites a los derechos de explotación (Tema 9 pag 309)&lt;/h2&gt;

&lt;p&gt;El artículo 100 de la LPI establece  las actividades que pueden llevarse a cabo sin necesidad de solicitar autorización al autor o al titular de los derechos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Corrección de errores y la transformación del programa podrá realizarse siempre que se requiera para lograr su correcta utilización de cara a lograr los fines previstos en la licencia.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Copia de seguridad, se reconoce sólo al usuario legítimo y solo si es necesaria para su uso.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;La ingenieria inversa, el usuario legítimo está autorizado a verificar las ideas implícitas del programa, pero no implica que pueda hacer uso de estas ideas en beneficio propio o ajeno.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Las versiones sucesivas están permitidas siempre que tengan originalidad suficiente como para considerarse obra derivada: traducciones, adaptaciones, revisiones, actualizaciones y anotaciones, compendios, resúmenes, extractos y arreglos musicales.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Descompilacion e interoperabilidad siempre que sea necesaria, se realice solo para obtener interoperabilidad y no para la producción o comercialización de programas semejantes.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;segunda-semana-julio-2016&quot;&gt;Segunda semana Julio 2016&lt;/h1&gt;

&lt;h2 id=&quot;1-criterios-clasificatorios-de-los-contratos-celebrados-en-la-red-de-acuerdo-a-la-forma-en-que-se-recoge-el-contrato-y-su-fuerza-probatoria-tema-3-pag-136&quot;&gt;1. &lt;a name=&quot;clasificacionForma&quot;&gt;&lt;/a&gt;Criterios clasificatorios de los contratos celebrados en la red: de acuerdo a la forma en que se recoge el contrato y su fuerza probatoria (Tema 3 pag 136)&lt;/h2&gt;

&lt;p&gt;Los contratos concluidos desde la red, es decir los contratos digitales, los perfeccionados mediante clicado o los concluiods mediante intercambio de mensajes de correo electrónico deben integrarse en la clasificación clásica, a saber:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Contratos que no requieren de una forma determinada para su existencia&lt;/li&gt;
  &lt;li&gt;Contratos que vienen recogidos en una forma determinadad solo a efectos de prueba (ad probationem)&lt;/li&gt;
  &lt;li&gt;Aquellos que requieren necesariamente para su existencia de una determinada forma.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-el-documento-de-identidad-electrónico-regulación-características-y-utilidad-ver-arriba&quot;&gt;2. El documento de identidad electrónico: regulación, características y utilidad. &lt;a href=&quot;#DNIE&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;3-síntesis-de-los-específicos-regímenes-jurídicos-en-atención-a-las-partes-contratantes-consideraciones-comunes-sobre-la-normativa-de-comercio-electrónico-tema-6-pag-254&quot;&gt;3. &lt;a name=&quot;comunesComercioElectronico&quot;&gt;&lt;/a&gt;Síntesis de los específicos regímenes jurídicos en atención a las partes contratantes: Consideraciones comunes sobre la normativa de comercio electrónico. (Tema 6 pag 254)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;No se aplica a todas las relaciones contractuales que pueden tener lugar desde la red. Por ejemplo no se aplica a contratos concluidos mediante el intercambio de correos electrónicos o aquellos en los que solo la aceptación ha sido tramitada por Internet.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Regula más cuestiones que las estrictamente vinculadas a la contratación en red. Pudiendo aplicarse a transmisiones de información no remuneradas ajenas al fenómeno contractual.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Está principalmente dirigida a regular determinados aspectos de los servicios publicitados u ofrecidos por prestadores de servicio profesionales.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;En materia de contratación, fija su atención en las relaciones que pueden tener lugar en una página web&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Las actuaciones no remuneradas se incluyen para exigir la identificación segura del prestador de servicio en caso de informaciones publicitarias no solicitadas, ofertas en masa, la tutela del correcto respeto de los derechos de contenido económico derivados de la PI y la lucha contra el anonimato en posibles actos ilícitos.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pueden distinguirse tres tipos de regímenes jurídicos aplicables a los contratos celebrados en Internet: contratación con consumidores, contratación entre profesionales y contratación entre particulares. Además, se tendrá en cuenta, dentro de cada uno de ellos, el tipo de instrumento o sistema: correo electrónico, página web, chat o videoconferencia.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;4-delitos-contra-la-propiedad-intelectual-ver-arriba&quot;&gt;4. Delitos contra la propiedad intelectual. &lt;a href=&quot;#delitosPI&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h1 id=&quot;septiembre-ord-2016&quot;&gt;Septiembre (Ord) 2016&lt;/h1&gt;

&lt;h2 id=&quot;1-beneficios-que-aporta-internet-a-la-contratación-reducción-del-coste-de-los-productos-y-servicios-y-su-precio-de-adquisición-tema-1-pag-42&quot;&gt;1. Beneficios que aporta Internet a la contratación: Reducción del coste de los productos y servicios y su precio de adquisición. (Tema 1 pag 42)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;La contratación a través de Internet debería facilitar la reducción de precios al eliminar el costo de los intermediarios comerciales, aunque incluye costes adicionales de nuevos intermediarios (publicidad, infraestructura)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Los costes de distribución desaparecen cuando el producto o servicio es de naturaleza inmaretial (p. ej. software) Pero no cuando es un producto material que deberá ser remitido al comprador.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;También se reducen costes en comunicaciones tradicionales (fax, teléfono) con respecto a las digitales.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Estos factores deberían abaratar el precio de los bienes y productos, pero en la práctica no siempre sucede así y los precios son equivalentes a los del comercio tradicional.&lt;/p&gt;

&lt;h2 id=&quot;2-el-criterio-subjetivo-de-determinación-del-régimen-jurídico-aplicable-al-contrato-tema-4-pag-139&quot;&gt;2. El criterio subjetivo de determinación del régimen jurídico aplicable al contrato. (Tema 4 pag 139)&lt;/h2&gt;

&lt;p&gt;Las características de las partes van a determinar el régimen jurídico aplicable:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Una relacioń mercantil (B2B) Cuando las partes sean profesionales que intercambien dentro de su ámbito de actuación propio.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Una relación civil (C2C P2P) cuando los sujetos que perfeccionan el contrato lo hacen en el ámbito de sus relaciones particulares, careciendo ambos de la condición de profesional.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Una relación de consumo (B2C) Cuando una de las partes actua como proveedor profesional y la otra actúa con un propósito ajeno a su actividad profesional.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;También han de tenerse en cuenta Las relaciones entre empresas y las administraciones públicas (B2A), los ciudadanos y las administraciones (C2A) y las relaciones entre las empresas y sus empleados (B2E)&lt;/p&gt;

&lt;p&gt;Es fundamental resaltar la problemática internacionalización que tiene lugar en el fenómeno contratual por Internet, que permite a los consumidores concluir contratos de carácter internacional, lo cual quedaba antes reservado a administraciones y empresas.&lt;/p&gt;

&lt;h2 id=&quot;3-principios-rectores-en-materia-de-protección-de-datos-de-caracter-personal-la-calidad-de-los-datos-tema-8-pag-285&quot;&gt;3. Principios rectores en materia de protección de datos de caracter personal: La calidad de los datos. (Tema 8 pag 285)&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Principio de calidad&lt;/em&gt;: los datos deben ser adecuados y pertinentes en relación con el ámbito y finalidad para el que se han obtenido. Esto engloba:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- _Principio de exactitud_ los datos han de ser precisos y mantenerse actualizados

- _Principio de finalidad_ impide que los datos sean tratados con fines diferentes o incompatibles con aquellos para los que se obtuvieron y deberán ser destruídos si dejan de ser pertinentes o necesarios.

- _Principio de lealtad_ Para la recogida de datos sólo podran utilizarse medios legales
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;4-delitos-contra-el-patrimonio-y-contra-el-orden-económico-estafas-defraudaciones-y-daños-tema-10-pag-327&quot;&gt;4. Delitos contra el patrimonio y contra el orden económico: Estafas, defraudaciones y daños. (Tema 10 pag 327)&lt;/h2&gt;

&lt;p&gt;Podemos llamar fraudes o estafas informáticas tanto a las realizadas a través de manipulaciones informáticas como a la fabricación de programas con esos fines.&lt;/p&gt;

&lt;p&gt;La estafa mediante manipulación informática (phising) señala como reos de estafa a&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“quienes con ánimo de lucro, y valiéndose de alguna manipulación informática o artificio semejante, consigan la transferencia no consentida de cualquier activo patrimonial en perjuicio de tercero”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;También se castiga la difusión o tenencia de programas que permitan la comisión de estafas, aunque no se hayan utilizado.&lt;/p&gt;

&lt;p&gt;Las defraudaciones de fluido eléctrico y análogas sancionan al &lt;strong&gt;“que hiciere uso de cualquier equipo terminal de telecomunicación, sin consentimiento de su titular, ocasionando a este un perjuicio”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;En cuanto a la regulación del Delito de Daños, se recogen dos modalidades:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Cusar daños a programas informáticos o documentos electrónicos mediante la destrucción o inutilización del soporte físico o lógico. Existiendo un tipo agravado cuando los daños son producidos mediante incendios, explosiones o otro medio de potencia destructiva.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Obstaculizar o interrumpir a través de diferentes medios, el funcionamiento de sistemas informáticos: el sabotaje informático. El borrado o modificación de los datos debe ser permanente.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;primera-semana-julio-2015&quot;&gt;Primera semana Julio 2015&lt;/h1&gt;

&lt;h2 id=&quot;1-criterios-clasificatorios-de-los-contrataos-celebrados-en-la-red-de-acuerdo-a-la-forma-en-que-se-recoge-el-contrato-y-su-fuerza-probatoria-ver-arriba&quot;&gt;1. Criterios clasificatorios de los contrataos celebrados en la red: de acuerdo a la forma en que se recoge el contrato y su fuerza probatoria &lt;a href=&quot;#clasificacionForma&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;2-el-documento-de-identidad-electrónico-regulación-características-y-utilidad-ver-arriba-1&quot;&gt;2. El documento de identidad electrónico: regulación, características y utilidad &lt;a href=&quot;#DNIE&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;3-síntesis-de-los-específicos-regímenes-jurídicos-en-atención-a-las-partes-contratantes-consideraciones-comunes-sobre-la-normativa-de-comercio-electrónico-ver-arriba&quot;&gt;3. Síntesis de los específicos regímenes jurídicos en atención a las partes contratantes: Consideraciones comunes sobre la normativa de comercio electrónico &lt;a href=&quot;#comunesComercioElectronico&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;4-delitos-contra-la-propiedad-intelectual-ver-arriba-1&quot;&gt;4. Delitos contra la propiedad intelectual &lt;a href=&quot;#delitosPI&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h1 id=&quot;segunda-semana-julio-2015&quot;&gt;Segunda semana Julio 2015&lt;/h1&gt;

&lt;h2 id=&quot;1-el-fomento-institucional-del-uso-de-internet-la-discutida-ver-arriba&quot;&gt;1. El fomento institucional del uso de internet: La discutida… &lt;a href=&quot;#discutida&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;2-el-documento-de-identidad-electrónico-regulación-características-y-utilidad-ver-arriba-2&quot;&gt;2. El documento de identidad electrónico: regulación, características y utilidad &lt;a href=&quot;#DNIE&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;3-la-prueba-de-los-contratos-concluidos-en-internet-con-firma-electrónica-la-transposición-en-españa-en-la-directiva-sobre-forma-electrónica-ver-arriba&quot;&gt;3. La prueba de los contratos concluidos en Internet con firma electrónica: la transposición en España en la Directiva sobre forma electrónica &lt;a href=&quot;#firmaElectronicaEs&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;4-la-protección-de-los-programas-de-ordenador-en-el-derecho-español-límites-a-los-derechos-de-explotación-ver-arriba&quot;&gt;4. La protección de los programas de ordenador en el Derecho Español: Límites a los derechos de explotación &lt;a href=&quot;#limitesExplotacion&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h1 id=&quot;septiembre-ord-2015&quot;&gt;Septiembre (Ord.) 2015&lt;/h1&gt;

&lt;h2 id=&quot;1-el-fomento-institucional-del-uso-de-internet-la-discutida-ver-arriba-1&quot;&gt;1. El fomento institucional del uso de internet: La discutida… &lt;a href=&quot;#discutida&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;2-el-documento-de-identidad-electrónico-regulación-características-y-utilidad-ver-arriba-3&quot;&gt;2. El documento de identidad electrónico: regulación, características y utilidad &lt;a href=&quot;#DNIE&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;3-la-prueba-de-los-contratos-concluidos-en-internet-con-firma-electrónica-la-transposición-en-españa-en-la-directiva-sobre-forma-electrónica-ver-arriba-1&quot;&gt;3. La prueba de los contratos concluidos en Internet con firma electrónica: la transposición en España en la Directiva sobre forma electrónica &lt;a href=&quot;#firmaElectronicaEs&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h2 id=&quot;4-la-protección-de-los-programas-de-ordenador-en-el-derecho-español-límites-a-los-derechos-de-explotación-ver-arriba-1&quot;&gt;4. La protección de los programas de ordenador en el Derecho Español: Límites a los derechos de explotación &lt;a href=&quot;#limitesExplotacion&quot;&gt;ver arriba&lt;/a&gt;&lt;/h2&gt;

&lt;h1 id=&quot;primera-semana-julio-2014&quot;&gt;Primera Semana Julio 2014&lt;/h1&gt;

&lt;h2 id=&quot;1-debilidades-que-plantea-esta-forma-de-contratación-internacionalidad-tema-1&quot;&gt;1. Debilidades que plantea esta forma de contratación: internacionalidad (Tema 1)&lt;/h2&gt;

&lt;h2 id=&quot;2-las-formas-electrónicas-regulación-tipos-y-funciones-de-contratación-tema-4&quot;&gt;2. Las formas electrónicas: regulación, tipos y funciones de contratación (Tema 4)&lt;/h2&gt;

&lt;h2 id=&quot;3-las-comunicaciones-comerciales-su-regulación-y-posible-repercusión-en-el-contrato-tema-6&quot;&gt;3. Las comunicaciones comerciales: su regulación y posible repercusión en el contrato (Tema 6)&lt;/h2&gt;

&lt;h2 id=&quot;4-la-libertad-informática-tema-7&quot;&gt;4. La libertad informática (Tema 7)&lt;/h2&gt;

&lt;h1 id=&quot;segunda-semana-julio-2014&quot;&gt;Segunda semana Julio 2014&lt;/h1&gt;

&lt;h2 id=&quot;1-debilidades-que-plantea-esta--forma-de-contratación-carácter-transversal-e-interdisciplinariedad-jurídica-tema-1-pag-49&quot;&gt;1. Debilidades que plantea esta  forma de contratación: carácter transversal e interdisciplinariedad jurídica (Tema 1 pag 49)&lt;/h2&gt;

&lt;p&gt;En la contratación por Internet, a menudo resulta difícil deslindar las fronteras correspondientes al Derecho público y privado, Derecho penal, Derecho fiscal, civil y/o mercantil.&lt;/p&gt;

&lt;p&gt;Desde una perspectiva territorial, pueden originarse dudas respecto a la aplicación del derecho comunitario, interno o internacional. Además, dentro del derecho privado, se combinan cuestiones de privacidad, protección de datos personales, propiedad intelectual e industrual, derecho contractual, etc.&lt;/p&gt;

&lt;p&gt;La finalidad de la Ley Modelo no es la de regular aspectos de otras disciplinas jurídicas.&lt;/p&gt;

&lt;h2 id=&quot;2-momento-y-lugar-de-la-perfección-del-contrato-en-internet-relevancia-jurídica-del-tema-tema-5-pag-195&quot;&gt;2. Momento y lugar de la perfección del contrato en Internet: Relevancia jurídica del tema (Tema 5 pag 195)&lt;/h2&gt;

&lt;p&gt;EL momento exacto de inicio del contrato es importante para poder determinar desde cuando son exigibles las obligaciones establecidas en él para las partes. También es necesario para poder aplicar otros derechos como la revocación o retirada de la aceptación, la transmisión de los riesgos de la cosa adquiriente, la aplicación de clausulas que impliquen periodos de tiempo como la resolución del contrato a distancia y para poder determinar la ley o norma aplicable en el tiempo a la relación contractual.&lt;/p&gt;

&lt;p&gt;También es fundamental determinar el lugar exacto de conclusión del contrato para poder determinar la &lt;strong&gt;ley o norma aplicable espacialmente&lt;/strong&gt;, el &lt;strong&gt;fuero jurisdicional competente&lt;/strong&gt; y el lugar de cumplimiento de las obligaciones recogidas en el negocio, a falta de una norma expresa que lo determine.&lt;/p&gt;

&lt;h2 id=&quot;3-la-presencia-de-condiciones-generales-de-contratación-tema-6-pag-220&quot;&gt;3. La presencia de condiciones generales de contratación (Tema 6 pag 220)&lt;/h2&gt;

&lt;p&gt;Los contratos operados desde una página web siguen un procedimiento de sucesión de pantallas
en el que la negociación de las cláusulas desaparece. Los más relevantes son los
“contratos en masa” a través de una página web, a los que siguen en importancia las subastas.&lt;/p&gt;

&lt;p&gt;Estos contratos en masa se caracterizan por poder hacer un contrato idéntico con multitud de personas, y
por carecer de la etapa previa en la que se negocia el contenido contractual.&lt;/p&gt;

&lt;p&gt;En este contexto, son las condiciones generales de contratación quienes representan el instrumento de
estandarización de las relaciones contractuales. El comprador deberá ser informado debidamente o deberá
haber aceptado para que resulten eficaces.&lt;/p&gt;

&lt;p&gt;La regulación española distingue entre un régimen jurídico amplio destinado a regular las “condiciones
generales” dirigidas a la contratación en general, y un régimen específico sobre las “cláusulas abusivas”
destinado a los consumidores, las que pese a que sean aceptadas por ellos, serán nulas cuando sean
declaradas abusivas.&lt;/p&gt;

&lt;p&gt;En los casos de contratación telefónica o electrónica será necesario que conste la aceptación de todas y cada
una de las cláusulas del contrato, sin necesidad de firma convencional.&lt;/p&gt;

&lt;p&gt;En Internet será suficiente manifestar la aceptación de las cláusulas mediante firma electrónica avanzada no
reconocida o simple, e incluso, si éstas están accesibles desde la web de forma clara y comprensible, ni
siquiera requerirán ser aceptadas mediante ninguna firma electrónica, siempre que esta aceptación venga
recogida en soporte electrónicos.&lt;/p&gt;

&lt;h2 id=&quot;4-la-ley-orgánica-151999-de-protección-de-datos-de-carácter-personal-derechos-de-los-afectados-tema-8&quot;&gt;4. La Ley Orgánica 15/1999 de Protección de Datos de Carácter Personal: Derechos de los afectados (Tema 8)&lt;/h2&gt;

&lt;p&gt;Los derechos establecidos por la LOPD son personales y gratuítos y pueden realizarse por cualquier cauce admitido en el Derecho que se incluya la identificación del aceptado, la petición que se formula y los documentos que la justifican, y son:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Derecho de información&lt;/strong&gt; permite al afectado saber quien conoce sus datos, y cómo y para qué van a ser utilizados y tratados.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Derecho de consulta&lt;/strong&gt; cualquier sujeto puede conocer los tratamientos de datos que existen, su finalidad y la identidad del responsable.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Derecho de impugnación de valores&lt;/strong&gt; permite al usuario rechazar decisiones que tengan efectos jurídicos y se hayan adoptado evaluando aspectos de su personalidad mediante el tratamiento de sus datos.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Derecho de acceso&lt;/strong&gt; los afectados podrán obtener gratuitamente información de los datos y las cesiones realizadas o que se puedan realizar.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Derecho a rectificación y cancelación&lt;/strong&gt; permite al afectado exigir la rectificación de los datos en función al principio de calidad, y la cancelación cuando ya no sean necesarios o se hayan cumplido los plazos legales atendiendo al principio de finalidad.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La cancelación de los datos no implica su borrado inmediato si no su bloqueo durante un tiempo y posterior borrado.&lt;/p&gt;

&lt;h1 id=&quot;septiembre-ordinaria-2014&quot;&gt;Septiembre Ordinaria 2014&lt;/h1&gt;

&lt;h2 id=&quot;1-comercio-electrónico-e-internet-tema-2-pag-95&quot;&gt;1. Comercio electrónico e Internet (Tema 2 pag 95)&lt;/h2&gt;

&lt;p&gt;No todo lo que se realiza en Internet es comercio electrónico ni todo el comercio electrónico se realiza a través de Internet. El comercio electrónico ya se realizaba antes mediante EDI, pero hay una serie de características que han hecho de Internet un medio idóneo para el avance del comercio electrónico y la sociedad de la información:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;La modalidad técnica de presentación de bienes y servicios (los documentos hipertextuales) que convierten los sitios comerciales en escaparates telemáticos desde los que además se puede concluir el contrato.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;El modo abierto de comunicación, que permite el acceso a la red a cualquier persona independientemente de su condición y lugar físico.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;El permitir la comunicación en las dos direcciones, lo que hace el servicio altamente interactivo.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;2-ámbito-de-aplicación-subjetivo-de-la-directiva-sobre-comercio-eletrónico-el-concepto-de-consumidor-en-las-relaciones-derivadas-de-un-servicio-de-la-sociedad-de-la-información-tema-4&quot;&gt;2. Ámbito de aplicación subjetivo de la Directiva sobre Comercio Eletrónico: El concepto de consumidor en las relaciones derivadas de un servicio de la sociedad de la información (Tema 4)&lt;/h2&gt;

&lt;p&gt;La directiva sobre comercio electrónico identifica al “consumidor” como “cualquier persona física que con un propósito ajeno al de su actividad económica, negocio o profesión” Pero en algunos paises de la Unión, como en España, también se consideran consumidores a las personas jurídicas, con lo que se pueden producir divergencias de criterios en contrataciones internacionales donde la normativa no coincida en la definición de consumidor, y en dificultades para establecer si se trata de una relación de consumo o no.&lt;/p&gt;

&lt;h2 id=&quot;3-principios-rectores-en-materia-de-protección-de-datos-de-carácter-personal-principio-de-información-y-el-consentimiento-del-interesado-tema-8-pag-285-y-286&quot;&gt;3. Principios rectores en materia de protección de datos de carácter personal: Principio de Información y el Consentimiento del interesado (Tema 8 pag 285 y 286)&lt;/h2&gt;

&lt;p&gt;El principio de información es fundamental para que el interesado pueda ejercer sus derechos, ya que si el afectado no sabe que sus datos están siendo almacenados difícilmente podrá acceder a ellos o pedir que se modifiquen o destruyan los documentos de acuerdo al principio de calidad, finalidad y lealtad. El afectado debe conocer: la existencia del fichero, la finalidad y la identidad de su propietario. Si está obligado o no a facilitar los datos. Las consecuencias que se derivan de de la obtención de los datos o de su negativa a suministrarlos. La posibilidad de ejercer los derechos de acceso, modificación, cancelación y oposición.&lt;/p&gt;

&lt;p&gt;El consentimiento del interesado  puede ser explícito o tácito,en el caso de datos de carácter sensible (opinión política, orientación sexual, religión, etc) debe prestarse expresamente y por escrito.&lt;/p&gt;

&lt;h2 id=&quot;4-las-bases-de-datos-y-el-derecho-sui-generis-objetivo-de-protección-y-contenido-del-derecho-sui-generis-tema-9-pag-315&quot;&gt;4. Las bases de datos y el derecho “sui generis”: Objetivo de protección y Contenido del derecho “sui generis” (Tema 9 pag 315)&lt;/h2&gt;

&lt;p&gt;Las bases de datos, aun muchas veces consisten en contenido no original (bbdd exahustivas), el alto coste y la creciente competencia en el mercado internacional hacían difícil la inversión en este tipo de infraestructuras. Para proteger a los fabricantes e incentivar la creación de bases de datos se crea este derecho “ui géneris” que es independiente del derecho de PI y el derecho de propiedad industrial. El derecho “sui generis” de las bases de datos otorga a sus fabricantes la potestad de autirizar o prohibir el acceso y utilización de la totalidad o una parte sustancial de su contenido. Este derecho es de 15 años en lugar de 60 como el las creacions artísticas y el software, pero serán prorrogables si se demuestra que ha sido necesaria una inversión importante para su mantenimiento y/o actualización a lo largo del tiempo.&lt;/p&gt;

&lt;h1 id=&quot;otros-epígrafes&quot;&gt;Otros epígrafes:&lt;/h1&gt;

&lt;p&gt;Otros resúmenes hechos estudiando el resto de epígrafes:&lt;/p&gt;

&lt;h3 id=&quot;principios-rectores-en-materia-de-protección-de-datos-de-caracter-personal-principio-de-información&quot;&gt;Principios rectores en materia de protección de datos de caracter personal: Principio de información:&lt;/h3&gt;

&lt;p&gt;Los titulares de los datos tienen derecho a saber quien va a realizar el tratamiento de los datos y con qué fines y deberán ser informados expresamente y de forma inequívoca de:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- La existencia del fichero en el que los datos van a ser incorporados, la finalidad que se persigue y los destinatarios de la información

- si está obligado o no a facilitar los datos

- las consecuencias que se derivan de la obtención de los datos o de la negativa a facilitarlos

- la posibilidad de ejercer los derechos de acceso, rectificación, cancelación y oposición

- la identidad y dirección del responsable del tratamiento, o en su caso, de su representante
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;principios-rectores-en-materia-de-protección-de-datos-de-caracter-personal-el-consentimiento-del-interesado&quot;&gt;Principios rectores en materia de protección de datos de caracter personal: el consentimiento del interesado.&lt;/h3&gt;

&lt;p&gt;El consentimiento del intersado es condición indispensable para que el tratamiento de datos de carácter personal sea lícito. En el caso de datos sensibles debe prestarse expresamente y por escrito. La legislación contempla excepciones para datos públicos recabados con intereses legítimos o para el ejercicio de las funciones de las Administraciones públicas&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Introducción a Node.js</title>
   <link href="http://juanmirod.github.io/2017/08/09/introduccion_nodejs.html"/>
   <updated>2017-08-09T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/08/09/introduccion_nodejs</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; es un entorno de ejecución de JavaScript que utiliza el motor V8 de Google. La historia de JavaScript y de Node.js es curiosa porque casi parece que todo surgió por accidente. JavaScript es conocido por haber sido &lt;a href=&quot;/public/javascript10days.pdf&quot;&gt;diseñado en 10 días por Bredan Eich&lt;/a&gt; y por sus &lt;a href=&quot;https://www.destroyallsoftware.com/talks/wat&quot;&gt;inconsistencias&lt;/a&gt;, pero aun así, se ha convertido en el el lenguaje de facto de la web. La imposición tecnológica de los navegadores, unido a la bajísima curva de aprendizaje han hecho de JavaScript el lenguaje con más crecimiento de los últimos tiempos. Herramientas como jQuery, Mootools y Backbone, Lodash, Angular, React… Han ido evolucionando la arquitectura de un lenguaje dinámico en principio carente de estructura. JS es en la actualidad uno de los lenguajes más utilizados y de mayor crecimiento. Con lo que era inevitable que los desarrolladores de JavaScript quisieran usar el lenguaje fuera de los navegadores. Como dice la Ley de Atwood:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Any application that can be written in JavaScript, will eventually be written in JavaScript &lt;a href=&quot;https://blog.codinghorror.com/the-principle-of-least-power/&quot;&gt;ver más&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Antes de Node.js hubo varios intentos de establecer un entorno de ejecución para JavaScript fuera de los navegadores. Los programadores querían sacar JavaScript del corsé del navegador, querían poder hacer aplicaciones, modificar ficheros y acceder al hardware. Una historia muy entretenida sobre los inicios de Node.js y npm la cuenta el propio Issac Z. Schlueter (creador de npm) &lt;a href=&quot;http://blog.izs.me/post/157295170418/my-first-npm-publish&quot;&gt;en su blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; Node.JS y npm se convirtieron en el entorno de ejecución de JavaScript en el servidor. Ahora podemos utilizar el mismo lenguaje para desarrollar en el servidor y en el cliente en el caso del desarrollo web, aunque también hay gente usando Node para ioT, para robots, para herramientas de línea de comandos, etc.&lt;/p&gt;

&lt;h2 id=&quot;instalación-y-el-repl&quot;&gt;Instalación y el REPL&lt;/h2&gt;

&lt;p&gt;Para instalar Node.js en Windows o en Mac, basta con ir a la página principal y descargar el instalador. Si usas Ubuntu, solo necesitamos un par de comandos:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install -y nodejs

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Si usas otra distribución de Linux, &lt;a href=&quot;https://nodejs.org/en/download/package-manager/#installing-node-js-via-package-manager&quot;&gt;mira aquí&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Una vez instalado podemos comprobar que la versión es la correcta (actualmente la versión LTS es la 6.x) escribiendo&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
node &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Para ejecutar el intérprete de Node, el REPL, simplemente escribimos el comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node&lt;/code&gt; y el terminal pasará a ser una consola de JavaScript en la que podremos ejecutar nuestro código.&lt;/p&gt;

&lt;p&gt;El REPL (siglas del inglés Read Eval Print Loop) es una consola que ejecuta cada expresión en JavaScript que le demos y devuelve el resultado de la expresión inmediatamente. Por ejemplo si escribimos:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 2 + 2
4

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4&lt;/code&gt; es el resultado de la expresión &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2 + 2&lt;/code&gt;, otro ejemplo&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; console.log&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Hola Mundo&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;s1&quot;&gt;&apos;Hola Mundo&apos;&lt;/span&gt;
undefined

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;‘Hola mundo’ es la salida que produce &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log(&apos;Hola Mundo&apos;)&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undefined&lt;/code&gt; es lo que devuelve la función. También podemos definir funciones y variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;globales&lt;/code&gt; que podremos usar a continuación:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
&lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En las versiones actuales de Node.js tenemos soporte de prácticamente la totalidad de la especificación de ES2015, con lo que podríamos escribir la función de arriba de otra forma:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El REPL es muy útil para probar pequeñas funciones y expresiones, yo cada vez lo utilizo más a menudo y los ejemplos de este blog suelen estar escritos de forma que sean fáciles de probar en el REPL. La ventaja de tener una respuesta inmediata a una duda de código es invaluable y normalmente no nos damos cuenta de eso hasta que lo probamos.&lt;/p&gt;

&lt;h2 id=&quot;módulos-y-npm&quot;&gt;Módulos y npm&lt;/h2&gt;

&lt;p&gt;Node no es solo el REPL, también podemos ejecutar ficheros. Solo tenemos que crear un fichero con el código javascript que queramos ejecutar y pasárselo al comando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;console.log(&quot;Hello Node&quot;)&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; hello.js
node hello.js
// Hello Node

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cada fichero JavaScript es un módulo para Node.js y si queremos usar alguna función definida dentro del fichero primero tendremos que exportarla. Por ejemplo creemos el fichero &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;factorial.js&lt;/code&gt; con el siguiente contenido:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Si ejecutamos ese fichero veremos que no pasa nada.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
node factorial.js 


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Nuestro módulo no hace nada a parte de definir una función y exportarla, pero desde el propio REPL o desde otro fichero Node.js podremos importar esta función y utilizarla:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;./factorial.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;factorial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;120&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;¿Mola eh? Ya tenemos un mecanismo para escribir código, encapsularlo en módulos y ejecutarlo. Esta es la base del desarrollo en Node, tan sencillo como eso.&lt;/p&gt;

&lt;p&gt;Node trae una serie de módulos básicos que podemos utilizar a modo de &lt;a href=&quot;https://nodejs.org/dist/latest-v6.x/docs/api/&quot;&gt;librería estandard&lt;/a&gt; Pero uno de los puntos fuertes de Node.js es el haberse mantenido flexible gracias a tener una librería estandar muy pequeña.&lt;/p&gt;

&lt;p&gt;Ese es también el punto fuerte de npm. &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm&lt;/a&gt; es un repositorio centraliazdo de módulos para Node.js En la comunidad de Node.js y npm la filosofía también es la de módulos pequeños que hagan una sola cosa, parecido a lo que ocurre con los comandos de Unix. Esto hace el lenguaje más fácil de componer, reordenar y modificar y tiene un gran potencial. Ahora mismo npm es el repositorio con mayor número de módulos de código abierto de todos los lenguajes y su número sigue creciendo a mayor velocidad que todos los demás.&lt;/p&gt;

&lt;p&gt;npm se instala en nuestro sistema junto con Node.js y podemos usarlo para instalar cualquier paquete de forma global o local a nuestro proyecto. Un proyecto es simplemente una carpeta donde hemos ejecutado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm init&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;hello
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;hello
npm init

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Al ejecutar este comando el programa nos hará algunas preguntas sobre el proyecto y creará un fichero &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; con la configuración mínima. Si solo queremos probar a instalar algunos paquetes podemos ejecutar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm init -y&lt;/code&gt; para crear este fichero y npm usará la configuración mínima por defecto y el nombre de la carpeta como nombre del proyecto.&lt;/p&gt;

&lt;p&gt;Ahora podemos instalar cualquier paquete del registro ejecutando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt; Por ejemplo podemos instalar &lt;a href=&quot;http://expressjs.com&quot;&gt;expressjs&lt;/a&gt;, una serie de librerías para crear un servidor web:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--save&lt;/span&gt; express

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El modificador &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--save&lt;/code&gt; indica a npm que queremos que guarde esta dependencia en el fichero del proyecto. Con express instalado localmente, podemos crear nuestro fichero &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.js&lt;/code&gt; con este contenido:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;express&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;express&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;express&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hola desde Node!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Servidor creado y escuchando en el puerto 3000!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y ejecutarlo en la consola:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
node index.js

Servidor creado y escuchando en el puerto 3000!

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Si abres un navegador y vas a ‘localhost:3000’ verás el mensaje ‘Hola desde Node!’&lt;/p&gt;

&lt;p&gt;Esas son las herramientas básicas de desarrollo en Node.js. Módulos, un entorno de ejecución, el repositorio central de npm y JavaScript. Con lo que sabes ya puedes ir a explorar un poco el registro de npm o la documentación de express y comenzar a desarrollar tu propio servidor web :D&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Función slice en JavaScript</title>
   <link href="http://juanmirod.github.io/2017/07/23/javascript-slice.html"/>
   <updated>2017-07-23T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/07/23/javascript-slice</id>
   <content type="html">&lt;p&gt;Siguiendo con las funciones que suelo tener que consultar y que espero que estos artículos me ayuden a superar, está slice.&lt;/p&gt;

&lt;p&gt;Este es el segundo de una serie de artículos sobre funciones en javascript y ejemplos de uso. Puedes ver el primero &lt;a href=&quot;http://juanmirod.github.io/2017/07/19/javascript-split.html&quot;&gt;aquí&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;slice&quot;&gt;Slice&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/artur-rutkowski-112531-unsplash.jpg&quot; alt=&quot;Foto de un trozo de pan y un cuchillo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Slice, como su nombre indica, toma un &lt;em&gt;“trozo”&lt;/em&gt; de un array, indicado por un índice de inicio y un índice final (no incluido) Slice no modifica el array original y hace una copia &lt;em&gt;“superficial”&lt;/em&gt; con lo que si el array contiene referencias a objetos, slice no clonará esos objetos, sino solo la referencia.&lt;/p&gt;

&lt;p&gt;Si el índice inicial es negativo, se considerará que se comienza en el elemento -N comenzando por el final, si se omite se tomará como 0.
Si el segundo índice se omite, se tomará como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array.length&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Veamos algunos ejemplos para dejar claro su uso:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// constante para mejor legibilidad de los ejemplos&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Ejemplos con números&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Tomar los n primeros elementos&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [0,1,2,3,4]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// comienzo y final del slice&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [3,4]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Tomar elementos del final&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [7,8]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Puedes usar slice con arrays con valores de cualquier tipo de datos escalar&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;computerScientists&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;John Hughes&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Ada Lovelace&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Barbara Liskov&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Grace Hopper&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Alan Key&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;John McCarthy&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;computerScientists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;Ada Lovelace&quot;, &quot;Barbara Liskov&quot;, &quot;Grace Hopper&quot; ]&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;computerScientists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;John Hughes&quot;, &quot;Ada Lovelace&quot;, &quot;Barbara Liskov&quot; ]&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;computerScientists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;Alan Key&quot;, &quot;John McCarthy&quot; ]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Clonar un array de valores con slice&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;computerScientists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [&apos;John Hughes&apos;, &apos;Ada Lovelace&apos;, &apos;Barbara Liskov&apos;, &apos;Grace Hopper&apos;, &apos;Alan Key&apos;, &apos;John McCarthy&apos;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ¡¡ Pero ojo con los objetos !!&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;punto1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;punto2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;punto1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;punto2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ Object, Object ]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;punto1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;punto2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;punto1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// { x: 7, y: 10 } ¡¡Hemos modificado &apos;punto1&apos;!!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Función split en JavaScript</title>
   <link href="http://juanmirod.github.io/2017/07/19/javascript-split.html"/>
   <updated>2017-07-19T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/07/19/javascript-split</id>
   <content type="html">&lt;p&gt;Todos los lenguajes tienen las típicas funciones que tenemos que consultar cada vez que las usamos. Bien porque no las usamos todos los días, bien porque se parecen a otras de la librería estándar o nos recuerdan a una función parecida en otro lenguaje. Lo cierto es que es un engorro y nos hace sentir tontos y olvidadizos y sentimos el &lt;em&gt;síndrome del impostor&lt;/em&gt; colgándose de nuestra espalda.&lt;/p&gt;

&lt;p&gt;Este es el primero de una serie de artículos cortitos con ejemplos de algunas de esas funciones en JavaScript. La mejor forma de recordar una función es usarla y verla en muchos ejemplos, así que espero que depués de escribir estos aŕtículos no tenga que consultar más MDN para estas funciones y espero que de camino sean de utilidad a alguien.&lt;/p&gt;

&lt;h2 id=&quot;split&quot;&gt;Split&lt;/h2&gt;

&lt;p&gt;Esta función sirve para dividir una cadena en partes utilizando un carácter delimitador, devolviéndonos un array con los &lt;em&gt;“trozos”&lt;/em&gt;. También admite un segundo parámetro opcional que indica cuántos elementos queremos que nos devuelva.&lt;/p&gt;

&lt;p&gt;Pero lo mejor es ver algunos ejemplos. Los ejemplos están escritos de forma que se pueden comprobar pegándolos en el REPL de node o en la consola del navegador (F12). Por eso no he creado funciones que los contengan o permitan generalizarlos. Copialos, úsalos, trastéalos es la mejor forma de tener &lt;strong&gt;split&lt;/strong&gt; grabada en tu memoria.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Podemos usar split para obtener las palabras de una oración&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;Podemos&quot;, &quot;usar&quot;, &quot;split&quot;, &quot;para&quot;, &quot;obtener&quot;, &quot;las&quot;, &quot;palabras&quot;, &quot;de&quot;, &quot;una&quot;, &quot;oración&quot; ]&lt;/span&gt;

&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;javascript,split,snippet,samples&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;javascript&quot;, &quot;split&quot;, &quot;snippet&quot;, &quot;samples&quot; ]&lt;/span&gt;

&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;javascript,split,snippet,samples&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;javascript&quot;, &quot;split&quot; ]&lt;/span&gt;

&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Podemos usar split para obtener las palabras de una oración&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;Podemos&quot;, &quot;usar&quot;, &quot;split&quot; ]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// convirtiendo un fichero csv con split y map&lt;/span&gt;
&lt;span class=&quot;s2&quot;&gt;`Ada Lovelace,English,1815
Grace Hopper,American,1906
Alan Turin,English,1954`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Array [ Array[3], Array[3], Array[3] ]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// inviertiendo una cadena con split y reverse&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;javascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// &quot;tpircsavaj&quot;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// split se puede usar con expresiones regulares&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Ada Lovelace   ,  English ,   1815&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\s&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\s&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;Ada Lovelace&quot;, &quot;English&quot;, &quot;1815&quot; ]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// usando expresiones regulares también podemos usar varios delimitadores diferenciados&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello, how are you?&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/,|&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\s&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;+/g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &apos;Hello&apos;, &apos;&apos;, &apos;how&apos;, &apos;are&apos;, &apos;you?&apos; ] &lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// y si usamos () nos devuelve los delimitadores&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Ada Lovelace   ,  English ,   1815&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;(\s&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*,&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\s&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;Ada Lovelace&quot;, &quot;   ,  &quot;, &quot;English&quot;, &quot; ,   &quot;, &quot;1815&quot; ]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// podemos encontrar todas las palabras diferentes de un texto con split, Set y Array.from&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;texto texto largo con con con muchas palabras&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ &quot;texto&quot;, &quot;largo&quot;, &quot;con&quot;, &quot;muchas&quot;, &quot;palabras&quot; ]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hasta aquí con los ejemplos con split. Si tienes algún otro ejemplo interesante o tienes alguna duda, puedes colaborar en &lt;a href=&quot;https://github.com/juanmirod/juanmirod.github.io/blob/master/_posts/2017-07-19-javascript-split.markdown&quot;&gt;este artículo en github&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Introducción a programación funcional con JavaScript</title>
   <link href="http://juanmirod.github.io/2017/06/16/introduccion-programacion-funcional-javascript.html"/>
   <updated>2017-06-16T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/06/16/introduccion-programacion-funcional-javascript</id>
   <content type="html">&lt;h1 id=&quot;introducción&quot;&gt;Introducción&lt;/h1&gt;

&lt;p&gt;La programación funcional parece que por fin va ganando más y más adeptos gracias a nuevos lenguajes como Scala, Clojure o Elm y a nuevos frameworks y librerías como Lodash, Ramda, React o Redux, que aunque no son puramente declarativos, sí que utilizan patrones y herramientas de la programación funcional.&lt;/p&gt;

&lt;p&gt;Los lenguajes funcionales siempre han estado ahí. Desde el comienzo de la informática, cuando Alonzo Church (profesor de Alan Turing, que luego escribiría con él la &lt;a href=&quot;https://en.wikipedia.org/wiki/Church%E2%80%93Turing_thesis&quot;&gt;Tésis de Church-Turing&lt;/a&gt;) definiera el Cálculo Lambda. Su historia está plagada de grandes nombres y grandes éxitos. Pero a la industria nunca le ha terminado de convencer y fue optando siempre por opciones imperativas, como ADA, C, PASCAL, Java o C#.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/1024px-HL_Stencil.jpg&quot; alt=&quot;Imagen del símbolo lamba pintado en una pared como referencia al videojuego Half Life&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hoy en día todos los grandes lenguajes van introduciendo conceptos de la programación funcional, he incluso hemos visto aparecer alternativas híbridas de todo tipo: Scala y Clojure para Java, F# para C#, o las librerías de Reactive Programming para varias plataformas… Además, lenguajes como Erlang/Elixir o Elm están demostrando que la programación funcionar se puede aplicar con mucho éxito a ciertas aplicaciones y hacer el desarrollo más fiable y fácil de mantener.&lt;/p&gt;

&lt;p&gt;JavaScript, desde su concepción es un lenguaje funcional y las ideas principales que le dan forma, las clausuras, las funciones como valores, la delegación de prototipos y la declaración de objetos sintácticamente son ideas tomadas de los lenguajes Scheme y Self. Por eso JavaScript se adapta bastante bien a la programación funcional. Además, ES6 añade algunas nuevas funcionalidades muy interesantes para el desarrollo funcional como la notación que expande elementos iterables con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;...&lt;/code&gt; o las funciones con la flecha gruesa &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Si eres desarrollador de JavaScript puede que hayas visto algunos ejemplos usando estas herramientas que te hayan resultado extraños. El código es más corto y conciso. Casi puedes leerlo como si fuera un fichero de configuración más que código porque es más declarativo, pero para entenderlo de verdad y utilizarlo es necesario conocer algunas funciones y patrones que hacen que todo encaje. Y lo que es más importante, la forma de escribir y leer el código cambia.&lt;/p&gt;

&lt;p&gt;Voy a explicar algunos patrones útiles y ejemplos prácticos de como utilizar la programación funcional para mejorar la legibilidad y la fiabilidad de nuestro código en JavaScript sin necesidad de aprender un nuevo lenguaje o cambiar nuestro flujo de trabajo.&lt;/p&gt;

&lt;p&gt;Puedes introducir este código desde YA en tus proyectos y no tendrás que cambiar nada. (Bueno, salvo si aun no usas ES6, cosa que te recomiendo desde ya, uses o no un estilo funcional en tu código.)&lt;/p&gt;

&lt;h1 id=&quot;qué-es-la-programación-funcional&quot;&gt;¿Qué es la programación funcional?&lt;/h1&gt;

&lt;p&gt;Antes de nada me gustaría aclarar este concepto. En este caso vamos a entender como programación funcional aquella que utiliza las funciones como piedra angular del desarrollo en lugar de los objetos o las clases. Además daremos prioridad a escribir funciones puras siempre que sea posible, aislando los efectos colaterales y utilizando librerías o módulos para separarlos del resto de la lógica.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;¿Funciones puras, efectos colaterales?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Son dos términos directamente relacionados. Se puede entender muy fácilmente lo que es una función pura si se sabe lo que son los efectos colaterales o secundarios (side-effects en inglés):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Efectos colaterales&lt;/strong&gt; son todas aquellas modificaciones que haga una función que estén fuera de su ámbito. Como modificar o crear una variable global, escribir algo a stdout, mostrar un gráfico en pantalla, escribir un fichero en el disco duro, acceder a una base de datos… Cualquier cosa que no sea operar sobre sus parámetros y variables locales es un efecto colateral.&lt;/p&gt;

&lt;p&gt;Ahora podemos definir muy fácilmente una &lt;em&gt;Función pura&lt;/em&gt; como aquella que no produce ningún efecto colateral. Las funciones puras son fáciles de usar, de testar y de leer y tienen la ventaja de que siempre van a producir la misma salida al darle los mismos parámetros. No dependen de ningun estado externo o configuración.&lt;/p&gt;

&lt;p&gt;Claro está, solo con funciones puras no se puede construir un programa. Sería un programa sin ningún tipo de feedback, ni si quiera podríamos saber si se ha ejecutado correctamente o no. Por eso hablo de separar las funciones puras de las que no lo son.&lt;/p&gt;

&lt;p&gt;Sobre el tema de crear un nucleo de funciones puras y una serie de plugins o módulos alrededor que conecten el núcleo con el mundo real hay mucho que hablar también, sobre todo recomiendo el video de Bernhardt &lt;a href=&quot;https://www.destroyallsoftware.com/talks/boundaries&quot;&gt;Boundaries&lt;/a&gt; pero eso es un tema más de arquitectura y hoy vamos a centrarnos en cómo desarrollar estas funciones y combinarlas para crear sistemas fáciles de testar, mantener y expandir.&lt;/p&gt;

&lt;h2 id=&quot;herramientas-de-desarrollo-funcional-en-javascript&quot;&gt;Herramientas de desarrollo funcional en JavaScript&lt;/h2&gt;

&lt;p&gt;Vamos a hacer un repaso por las herramientas del lenguaje que podemos usar para utilizar funciones puras como base principal para nuestro código. Intentaré ir desde las funcionalidades más fáciles o conocidas a las más ajenas a la mayoría.&lt;/p&gt;

&lt;p&gt;No pretendo que esta sea una guía exhaustiva o prescriptiva de cómo programar. Simplemente son una serie de funciones y patrones que pueden ayudar a hacer el código más conciso, legible o testable. Como todas las técnicas, patrones y librerías, no hay balas de plata. No pretendo decir que solo debas programar así o que la POO no sirva para nada. Cada cosa tiene su lugar, hay ámbitos donde la POO encaja mejor y otros donde lo hace la programación funcional, lugares donde es mejor usar Observables o aplicaciones que puedes resolver con jQuery. Al final yo veo escribir código como escribir un texto: cuando más vocabulario y más conocimiento tengas, mejor serás capaz de adaptarte y de describir el problema.&lt;/p&gt;

&lt;p&gt;En el código de los ejemplos seguiré algunas convenciones de código y herramientas de ES6 para ser más conciso y conseguir una notación más funcional y limpia. Además el código de los ejemplos pretende ser lo más simple e ilustrativo posible para que hacer llegar lo mejor posible cada idea, no pretende ser un código correcto o general que pueda usarse directamente en una aplicación.&lt;/p&gt;

&lt;p&gt;Este estilo al principio puede resultar un poco extraño o más familiar, según tu bagaje como desarrollador. Si te resulta raro te pido que le des una oportunidad y verás como rápidamente ves que al ser más breve y más declarativo, es más fácil de leer y de escribir y puede mejorar mucho tu código JavaScript.&lt;/p&gt;

&lt;p&gt;Como guía inicial, para aquellos que no estén familiarizados con ES6, utilizaré las funciones con flecha en la mayoría de los ejemplos. Esta es la sintaxis, junto a la equivalencia en ES5 (no hablo de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this&lt;/code&gt; porque en todos estos ejemplos usaremos funciones independientes que no dependen del objeto de contexto):&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;// funciones con flecha &lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* aquí el código */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* aquí el código */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Si la función sólo tiene un argumento, se puede prescindir de los paréntesis:&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* aquí el código */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* aquí el código */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Si la función sólo contiene una expresión que se retorna se puede prescindir de las llaves:&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Además, aunque no es muy común en según qué círculos, en JavaScript se puede no usar el ´;´ como delimitador de expresiones. Una de las funcionalidades del lenguaje, llamada ASI (Automatic Semicolon Insertion) hace que sean innecesarios, básicamente al ponerlos estamos haciendo el trabajo del compilador. Si queréis leer más sobre el tema os recomiendo &lt;a href=&quot;http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding&quot;&gt;este artículo de Isaac Z. Schlueter, el creador de npm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Todo esto era para decir que no habrá puntos y coma (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;&lt;/code&gt;) en el código :)&lt;/p&gt;

&lt;p&gt;La descomposición de objectos y arrays, una nueva sintáxis de &lt;strong&gt;ES6&lt;/strong&gt;, nos permite hacer cosas como estas:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; 
&lt;span class=&quot;c1&quot;&gt;// 10&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; 
&lt;span class=&quot;c1&quot;&gt;// 20&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 10&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 20&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;rest&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [30, 40, 50]&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 10&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 20&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Estas mismas transformaciones se pueden usar como parámetros en las funciones. Más sobre este tema &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment&quot;&gt;aquí&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;cómo-probar-los-ejemplos&quot;&gt;Cómo probar los ejemplos.&lt;/h2&gt;

&lt;p&gt;La forma más fácil de probar los ejemplos, modificarlos y crear alternativas es mediante el REPL de node. Hoy en día tanto Chrome como Firefox soportan ES6 &lt;a href=&quot;https://kangax.github.io/compat-table/es6/&quot;&gt;casi por completo&lt;/a&gt; Con lo que podemos probar también los ejemplos en la consola, pero presonalmente la consola de los navegadores siempre se me antoja pequeña e incómoda. Node soporta ES6 y todos los ejemplos se podrán correr en el REPL de node 6.x o superior. Para poder usarlo instalamos node y luego en el terminal escribimos:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; node
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; // a partir de aquí código :&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Más sobre cómo instalar Node.js y el REPL &lt;a href=&quot;http://juanmirod.github.io/2017/08/09/introduccion_nodejs.html&quot;&gt;aquí&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;bucles&quot;&gt;Bucles&lt;/h3&gt;

&lt;p&gt;Un primer paso para hacer nuestro código más funcional bastante común, es deshacerse de los bucles y utilizar las funciones .map/.filter/.reduce en su lugar. Estas funciones son parte de la librería estándar de JavaScript para Iterables y tienen una serie de propiedades muy interesantes. Usándolas &lt;strong&gt;no necesitaremos escribir contadores, con lo que reducimos una posible fuente de erratas&lt;/strong&gt; (¿quién no se ha equivocado al anidar dos bucles for y ha usado el contador que no debía?), son funciones que se pueden componer y ganamos en brevedad y simplicidad al ofrecer comportamientos más variados que los de un bucle normal.&lt;/p&gt;

&lt;p&gt;Además, estas tres funciones se caracterizan porque no alteran el array de entrada, sino que devuelven un nuevo array siempre, lo cual nos asegura que estamos trabajando de forma pura, sin crear efectos colaterales.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.map&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Map es la más básica de todas, además &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.map&lt;/code&gt; es una función omnipresente en la programación funcional que se utiliza no solo en iterables, sino también en promesas, streams y otros muchos tipos de datos.&lt;/p&gt;

&lt;p&gt;La función de map es tomar un array y una función y aplicar la función a cada uno de los elementos del array:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Por ejemplo:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// [2,4,6]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Otra notación que es muy concisa es la &lt;strong&gt;programación tácita&lt;/strong&gt; o &lt;strong&gt;pointfree notation&lt;/strong&gt; que quiere decir que, cuando una función toma un parámetro de entrada y se usa como argumento a otra función, podemos omitir el parámetro y la llamada queda de esta forma:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 

&lt;span class=&quot;c1&quot;&gt;// [2,4,6]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Espera un momento, ¿qué está pasando ahí?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lo que ocurre es que la función map espera una función y la llamará una vez por cada elemento del array, pasándole el elemento, como veíamos arriba. Así que es lo mismo pasarle la referencia &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;double&lt;/code&gt; que la función anónima, map tomará la función y la invocará de la misma forma. Aquí empezamos a ver la potencia de JavaScript como lenguaje funcional, no todos los lenguajes permiten usar las funciones como argumentos de otras funciones de forma tan sencilla y fácil de leer.&lt;/p&gt;

&lt;p&gt;Sigamos con las funciones de Iteradores.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;filter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Filter nos permite eliminar o seleccionar elementos de un array mediante un &lt;strong&gt;predicado&lt;/strong&gt; o filtro. Para ello le pasamos a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.filter&lt;/code&gt; nuestro predicado, que no es más que una función que se ejecuta por cada elemento y devuelve un booleano. Si el valor develto es &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; el elemento se devolverá en el nuevo array, si es &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; el elemento no estará en el nuevo array.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isEven&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isEven&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// [2,4,6]&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// [1,2,3,5,6]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Una buena ayuda para ayudar a recordar como usar filter es recordar el concepto de &lt;em&gt;predicado&lt;/em&gt;. Una función predicado es una función que nos devuelve un booleano, que devuelve &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; para cualquier entrada que le pasemos. algunos ejemplos de predicados útiles:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;// predicados&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isEven&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;greaterThan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;min&lt;/span&gt; 
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;whereNot&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ejemplos de uso&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isEven&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [2,4,6]&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;greaterThan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [4,5,6]&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [1,2,4,5,6]&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [{x: 35, y: 23}]&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;whereNot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [{x:1, y: 20}]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En los predicados de arriba también podemos ver algo que no he comentado hasta ahora: funciones que devuelven funciones. De igual forma que podemos pasar una función como argumento, podemos devolverlas como resultado. Así:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// es lo mismo que&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Esto es habitual en JavaScript y el truco está en que utilizamos el ámbito de la función para acceder al primer parámetro desde la función interior. Como Javascript tiene ámbito léxico (closure) podemos acceder a la variable sin importar donde o cuando hagamos la llamada:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notThree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;notThree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [1,2,4,5]&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;notThree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Puedes ver más sobre el ámbito léxico de JavaScript &lt;a href=&quot;http://juanmirod.github.io/2016/02/19/ambito-en-javascript.html&quot;&gt;aquí&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;reduce&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sin duda reduce es la función más difícil de entender de las tres y la que más miedo da cuando no la conoces. Pero también es muy potente y nos permite simplificar mucho el código cuando la usamos correctamente.&lt;/p&gt;

&lt;p&gt;Supongamos que queremos calcular la media aritmética de un array. Para eso normalmente haríamos un bucle para sumar los elementos y luego dividiríamos por el número de elementos:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; 
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;califications&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;califications&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 7&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este código se puede simplificar mucho usando reduce. Reduce toma el array y aplica la función que le demos, elemento a elemento, pasando en cada paso una copia del resultado, veamos el código y luego veremos cómo lo hace:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; 
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;califications&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;califications&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 7&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;¿Qué?? ¿Cómo??&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A todos nos pasa cuando vemos reduce por primera vez, veamos qué ha pasado. La función que le pasamos a reduce es bastante sencilla:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;current&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Simplemente toma el valor actual y lo suma al total que tiene acumulado. Es decir, podríamos escribirlo así:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; 
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;califications&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;califications&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 7&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El segundo argumento que le pasamos a reduce es el valor inicial &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;. Es decir que lo que estamos haciendo es decir:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Empezando con 0, toma todos los valores del array y súmalos uno a uno.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;La función que se le pasa a reduce recibe 4 argumentos y el segundo parámetro de reduce es opcional y es el valor inicial que se pasará como primer parámetro cuando se llame a la función por primera vez. Es importante saber que este también será el valor por defecto si el array sobre el que operamos está vacío:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;p&quot;&gt;[].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;originalArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y por tanto si tratamos de ejecutar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reduce&lt;/code&gt; sobre un array vacío sin pasarle un valor inicial, dos devolverá una excepción:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;p&quot;&gt;[].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;originalArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* ... */&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;TypeError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Reduce&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;empty&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;no&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;initial&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;native&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;repl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Ojo con la aridad de las funciones&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Algo a tener en cuenta cuando empezamos a utilizar estas funciones y la notación &lt;em&gt;point-free&lt;/em&gt; es la aridad de las funciones. Todas estas funciones reciben varios argumentos del array que las llama y debemos tener cuidado en utilizarlas correctamente para no caer en errores que nos puedan despistar, JavaScript es un lenguaje dinámico y aceptará casi cualquier cosa que le pasemos sin protestar:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [0,1,2,3,4,5,6]&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isEven&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [0,1,2,3,4,5,6]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En los dos casos anteriores lo que está pasando es que estamos devolviendo la referencia a la función en lugar de llamarla, y por extraño que parezca, en JavaScript &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!!((x) =&amp;gt; {}) === true&lt;/code&gt; y por tanto, el predicado siempre está devolviendo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; y mantenemos todos los valores del array.&lt;/p&gt;

&lt;p&gt;Esto puede volverse especialmente problemático si usamos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;currying&lt;/code&gt;, pero por supuesto tiene fácil solución. Volveremos sobre este punto un poco más adelante.&lt;/p&gt;

&lt;p&gt;Con estas tres funciones podemos librarnos de la práctica totalidad de los bucles de nuestro código y olvidarnos de tener que mantener contadores y de esa complicada sintaxis que los acompaña, lo cual hará el código más fácil de leer y nos dejará centrarnos en lo que queremos hacer con los elementos del array.&lt;/p&gt;

&lt;h3 id=&quot;funciones-de-orden-superior&quot;&gt;Funciones de orden superior&lt;/h3&gt;

&lt;p&gt;Otra herramienta funcional que hemos visto por encima en el apartado sobre bucles son las funciones de orden superior, es decir, las funciones que reciben otras funciones como parámetros o devuelven una función como salida.&lt;/p&gt;

&lt;p&gt;Un par de ejemplos que veíamos arriba son los generadores notEqual o where:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Estos funciones devuelven un predicado en función a los parámetros que reciben:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;

&lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [Function]&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notThree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;notThree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;notEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// false&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Esta forma de escribir y generar funciones nos permite crear fácilmente código más expresivo y que se puede componer. Cuando, como en estos casos, lo que hacemos es tomar una función que tomaría varios parámetros y tomarlos uno a uno, devolviendo cada vez una función que espera el siguiente parámetro estamos &lt;em&gt;currificando&lt;/em&gt; (del inglés currying) la función.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;f(x,y,z) =&amp;gt; f(x) =&amp;gt; g(y) =&amp;gt; h(z)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En el caso de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;where&lt;/code&gt;, podríamos escribirlo así:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Suponiendo que tenemos un array con objetos que hemos sacado de una base de datos y queremos buscar uno por id podríamos hacerlo así:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;whereIdIs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;whereIdIs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [{ id: 42, name: &apos;Ramón&apos; ... }]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sin usar filter ni currificar, suponiendo que queramos devolver siempre un array como hace filter, seguramente hubieramos acabado con un código tal que así:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [{ id: 42, name: &apos;Ramón&apos; ... }]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;La ventaja de where es que podemos usarlo para construir el predicado que necesitemos en cada momento. Si en otra función queremos buscar un usuario por nombre en lugar de por id, bastará con hacer:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;whereNameIs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// o simplemente usarlo sin crear un alias&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Ramón&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;currificar&lt;/em&gt; funciones es muy útil en general a hora de trabajar con funciones y componerlas y es una herramienta que combiene dominar para mejorar nuestro código en JavaScript. Hay librerías que ofrecen una función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curry&lt;/code&gt; que toma una función y nos la devuelve &lt;em&gt;currificada&lt;/em&gt; Vamos a probar a escribir nuestra propia función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curry&lt;/code&gt; para 2 parámetros:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;curry2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ejemplo&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;curriedAdd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;curry2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;curriedAdd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 5&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;add2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;curriedAdd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;add2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 5&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Por supuesto, la implementación se complica para n parámetros, pero para eso están las librerías funcionales que veremos al final del artículo, por ahora este simple ejercicio espero que sirva para mostrar lo que es &lt;em&gt;currificar&lt;/em&gt; una función.&lt;/p&gt;

&lt;h3 id=&quot;reduce-para-todo&quot;&gt;Reduce para todo&lt;/h3&gt;

&lt;p&gt;Cuando digo que &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reduce&lt;/code&gt; es muy potente me refiero a que en realidad, es la única función que necesitamos para operaciones iterativas. Tanto &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; como &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;filter&lt;/code&gt; pueden definirse con reduce. Poríamos tener estas tres operaciones como funciones independientes así:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doubles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;doubles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ 2, 4, 6, 8, 10 ]&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;evens&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;evens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [ 2, 4 ]&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 15&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 3&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;funciones-asíncronas&quot;&gt;Funciones asíncronas&lt;/h3&gt;

&lt;p&gt;Hasta ahora, las funciones de orden superior que hemos usado son funciones síncronas, es decir, que se ejecutan en el orden en el que están escritas. Incluso los bucles de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.map&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.filter&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.reduce&lt;/code&gt; se ejecutan de forma síncrona:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;After map&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 3&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// After map&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// undefined&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pero JavaScript está lleno de funciones asíncronas. Las funciones asíncronas son las que se ejecutan en otro momento, como resultado de un evento o de una respuesta a una petición. Usando el ejemplo anterior, pero ejecutando la función de forma asíncrona:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;asyncLog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;setImmediate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;asyncLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;After map&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// After map&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// undefined&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 3&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;No voy a extenderme en cómo funcionan las llamadas asíncronas en JavaScript, eso lo dejo para otro artículo sobre el Event Loop, pero dejémoslo en que las llamadas asíncronas se ejecutan fuera del orden en el que está escrito el programa. En JavaScript son muy comunes, pero el código de arriba no es muy limpio. Si realmente queremos escribir ‘After map’ después de transformar el array, ¿cómo lo hacemos?&lt;/p&gt;

&lt;p&gt;Para mejorarlo podemos usar las Promesas. Las promesas son un tipo de objeto que nos permite encapsular las llamadas asíncronas con un interface con el que podemos trabajar como si tuviéramos el resultado antes de ejecutarse la función. Siguiendo con el ejemplo anterior:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;asyncLog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;setImmediate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;asyncLog&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;After map&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 1&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 2&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 3&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// After map&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En este ejemplo le hemos dado la vuelta a la tortilla. asyncLog sigue siendo asíncrona, pero hemos encapsulado cada llamada en una promesa que se resuelve cuando la función se ejecuta y luego hemos usado &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Promise.all&lt;/code&gt; para ejecutar el &lt;em&gt;After map&lt;/em&gt; cuando todas las promesas se han resuelto. El código se vuelve a leer en el mismo orden en el que obtenemos los resultados, aunque las llamadas sean asíncronas.&lt;/p&gt;

&lt;p&gt;Este ejemplo es muy básico porque estas funciones no hacen más que loguear sus parámetros, para ver ejemplos reales y aprender más sobre las Promesas y cómo utilizarlas puedes ver &lt;a href=&quot;http://juanmirod.github.io/2016/11/25/promesas-en-javascript.html&quot;&gt;mi artículo dedicado sólo a ellas&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;composición&quot;&gt;Composición&lt;/h3&gt;

&lt;p&gt;Componer funciones es, simplemente, aplicarlas sucesivamente:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
(f·g)(x) = f(g(x)) 

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lo hacemos muchas veces sin darnos cuenta:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;average&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cuando aplicamos una función, y el resultado se lo pasamos a otra función, estamos componiendo funciones. Pero, cuando empiezas a usar más funciones puras, ocurre que tu código se va convirtiendo en una serie de composiciones. Los datos pasan por varias funciones hasta que tienes el resultado que quieres mostrar al usuario. &lt;strong&gt;La programación funcional hace que pasemos del paradigma de &lt;em&gt;“objetos que se pasan mensajes”&lt;/em&gt; al de “flujo de datos y transformaciones”_&lt;/strong&gt; y claro, todos esos paréntesis hacen el código poco legible y difícil de modificar.&lt;/p&gt;

&lt;p&gt;Por suerte no tenemos que hacerlo así, gracias a la expresión de arriba sabemos que podemos hacer esto:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;compose&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;functions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduceRight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;average&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Escribir el código de esta manera tiene varias ventajas: es más fácil de leer y es más fácil modificarlo al no tener que estar contando paréntesis. En cuanto a la legibilidad, a lo mejor el orden de las funciones puede despistar si no estás acostumbrado, pero para eso está &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipe&lt;/code&gt;, que hace lo mismo que compose, pero aplica las funciones de izquierda a derecha, o de arriba a abajo en nuestro ejemplo, lo que sí que encaja con la metáfora del flujo de datos y mantiene el orden de lectura habitual:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;functions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;average&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;round&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;condicionales-con-maybe-y-either&quot;&gt;Condicionales con Maybe y Either&lt;/h3&gt;

&lt;p&gt;Con las herramientas que hemos visto hasta ahora y algunas funciones auxiliares podemos escribir un código casi libre de paréntesis y de construcciones sintácticas. Conforme nos acostumbramos a encadenar promesas, usar funciones para transformar los datos y usar map/filter/reduce nos vamos dando cuenta de que podemos escribir muchas funciones como una serie de operaciones sobre la entrada, por ejemplo supongamos una hipotética app que pide los datos de unos clientes y quiere calcular la edad media:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;// Dado un nombre de una propiedad y un objeto, devuelve el valor de esa propiedad en el objeto&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pluck&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// función para poder usar map con aplicación parcial&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// calcula la media de un array de números&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;avgAge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;getUsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pluck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Salvo cuando tenemos que usar un condicional. Si en el ejemplo anterior tuvieramos que contemplar la opción de que algunos usuarios tengan la edad &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undefined&lt;/code&gt; se nos rompe nuestra bonita cadena de funciones y tenemos que volver a escribir sintaxis para el &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;// calcula la media de un array de números&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;No está mal, pero rompe un poco el estilo y sobre todo, no es DRY, cada vez que queremos comprobar esa condición en nuestra aplicación, tenemos que escribir ese mismo código. ¡A no ser que escribamos unas funciones que sustituyan las comprobaciones de nulidad!&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isNull&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;either&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;trueValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;falseValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;trueValue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;falseValue&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con ellas la función que calcula la media quedaría así:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;// calcula la media de un array de números&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; 
  &lt;span class=&quot;nx&quot;&gt;either&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pero hay una diferencia entre este código y el anterior. Este código siempre ejecuta las dos expresiones, mientras el condicional solo ejecutaba una de ellas, para tener la misma funcionalidad necesitamos envolver las expresiones en una función, de forma que solo se llame a una de las funciones después de comprobar el valos del predicado:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; 

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;either&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onTrue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onFalse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onTrue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;onFalse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// calcula la media de un array de números&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;avg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; 
  &lt;span class=&quot;nx&quot;&gt;either&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ahora sí que tenemos la misma funcionalidad que arriba, y la suma sólo se ejecutará si &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next&lt;/code&gt; no es &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; ni &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undefined&lt;/code&gt;. Este ejemplo puede parecer un poco extremo, estamos sustituyendo una de las piezas básicas de la sintaxis, una de las primeras cosas que aprendemos normalmente cuando nos enseñan a programar. Pero esa es la premisa de la programación funcional, utilizar funciones y tipos de datos para representar nuestro programa. Poco a poco estamos consiguiendo expresar cualquier expresión como una sucesión de funciones y eso es algo muy potente de cara a reusabilidad y testabilidad.&lt;/p&gt;

&lt;p&gt;En este último ejemplo a aparecido una función algo curiosa: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;k&lt;/code&gt;. La función constante, o &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;k&lt;/code&gt; es una función que siempre devuelve el mismo valor, y que nos sirve en este caso para poder pasarle a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;either&lt;/code&gt; una función en lugar de una expresión. Tal vez más adelante me aventure a mostrar otros combinators, pero si te ha llamado la atención esta función y quieres saber su origen puedes ver la &lt;a href=&quot;https://es.wikipedia.org/wiki/L%C3%B3gica_combinatoria#Ejemplos_de_combinadores&quot;&gt;entrada en la wikipedia sobre lógica combinatoria&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Este artículo está en pleno desarrollo, si te gusta este estilo de programación en Javascript vuelve pronto y seguramente encuentres nuevo contenido.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Ingeniería del software</title>
   <link href="http://juanmirod.github.io/2017/06/16/Ingenieria-del-software.html"/>
   <updated>2017-06-16T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/06/16/Ingenieria-del-software</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/public/img/ENIAC.jpg&quot; alt=&quot;foto del ENIAC uno de los primeros ordenadores, 1946, fuente: wikipedia&quot; title=&quot;Foto del ENIAC, 1946, fuente: wikipedia&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Este año ha coincidido que en el nuevo trabajo estoy haciendo más desarrollo de infraestructura y de arquitectura en general, lo que me obliga a pensar más en desarrollos escalables y a la vez he cursado la asignatura de Introducción a la Ingeniería del Software (IdS) por la UNED. Esto ha hecho que me fije en este problema desde varios puntos de vista y que lo tenga muy presente durante todo el año.&lt;/p&gt;

&lt;p&gt;Cuando hice la ITIS en Málaga, la Ingeniería del Software era una asignatura optativa y daba la casualidad de que el profesor era el peor de toda la facultad. Así que, pese a que me interesaba mucho, preferí ahorrármela por mi salud mental y emocional.&lt;/p&gt;

&lt;p&gt;Desde entonces he trabajado en empresas de diferentes tamaños y en proyectos de todo tipo, pero &lt;strong&gt;las metodologías de la IdS siempre han estado ausentes&lt;/strong&gt;. Incluso en empresas medianas o con bases de código de varios años y equipos de 20 o 30 personas, no solías ver Diagramas UML, ni documentos de diseño o de especificaciones, ni pruebas automatizadas, ni nada de eso.&lt;/p&gt;

&lt;p&gt;Lo más cercano fue cuando trabajé para el Ministerio de Educación, que teníamos una reunión mensual con acta, y aprobación del acta, y peticiones de permiso, y notificaciones para cada cambio. Pero todo esto era más para la facturación y para cubrirse las espaldas que de cara a la arquitectura o al desarrollo.&lt;/p&gt;

&lt;p&gt;Al final siempre pasa algo así: &lt;strong&gt;lo importante son las fechas de entrega, y por el camino se caen las especificaciones, el diseño y por supuesto las pruebas automáticas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Todo esto es lo que las metodologías ágiles vinieron a arreglar hace ya como 15 años, pero en la mayoría de las empresas siguen hablando de ellas como algo &lt;em&gt;“nuevo”&lt;/em&gt; de lo que no se fian mucho y que si se implementa se hace &lt;a href=&quot;https://www.martinfowler.com/bliki/FlaccidScrum.html&quot;&gt;mal y a medias&lt;/a&gt; al menos en España.&lt;/p&gt;

&lt;p&gt;En la asignatura de IdS de la UNED, para mi decepción, no se habla de la revolución de las metodologías ágiles sino que siguen anclados en el ciclo de vida en cascada o en V y demás metodologías del siglo pasado. Salvo una breve pero loable mención a Ken Beck y a XP, todo el libro de referencia está lleno de citas a libros y artículos de mediados de los 80, como si en una asignatura de arquitectura de computadores nos enseñaran a montar un ordenador con válvulas de vacío y cables.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/Colossus.jpg&quot; alt=&quot;foto del Colossus, el primer ordenador electrónico programable, 1943, fuente: wikipedia&quot; title=&quot;Foto del Colossus, 1943, fuente: wikipedia&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sin embargo, y pese a toda esa caspa, leer sobre arquitectura, diagramas, normalización de bases de datos, análisis de requisitos, etc. me ha ayudado a pensar mejor en cómo estructurar mi código y me ha enseñado algunos diagramas útiles para ayudarme a pensar en la arquitectura de mi aplicación o en cómo interactuan los diferentes componentes.&lt;/p&gt;

&lt;p&gt;Un diagrama en ocasiones es la mejor chuleta de apoyo a la documentación, es una forma de tener un esquema básico que te recuerda dónde estás en el desarrollo y qué otros módulos o aplicaciones interactúan con la tuya.&lt;/p&gt;

&lt;p&gt;Todo tiene su lugar. No se me ocurriría tratar de crear un documento de especificacion para la aplicación que estoy desarrollando &lt;strong&gt;¡Si ni quiera me han dado unos requisitos concretos! Estoy trabajando sobre unas cuantas frases de “quiero algo que haga esto y se parezca a aquello”&lt;/strong&gt; lo que suele ser habitual en los trabajos que he tenido, de ahí a unas especificaciones va un mundo ya no digamos a tratar de modelar todo en UML.&lt;/p&gt;

&lt;p&gt;En mi experiencia, los clientes, la gente de márketing o los propios CEOs o jefes de proyecto no tienen unas especificaciones concretas. Quieren algo que les solucione un problema o que mejore una forma de trabajar, pero no saben cómo hacerlo.&lt;/p&gt;

&lt;p&gt;Hoy en día, si la solución es algo concreto a lo que pueden poner nombre (un blog, un gestor de contabilidad, un ERM, un CSM, una tienda online, etc…) Ya existirá una solución paquetizada o un servicio que cubra esa necesidad. Cuando vamos al detalle, a donde hay que desarrollar algo a medida o nuevo, el cliente no sabe la funcionalidad que ese algo tendrá que tener, no sabe como alcanzarlo y normalmente no sabe ni la forma que debería tener.&lt;/p&gt;

&lt;p&gt;De ahí las metodologías ágiles: Hay que reducir el ciclo de retroalimentación lo más posible. Enseñar una funcionalidad al cliente, escuchar su opinión e iterar. Iterar rápido y corregir el rumbo en cada iteración para ir acercándonos mediante gradientes a la solución que busca el cliente, en lugar de salirnos por la tangente de un diseño que ideamos tras las primera semana de reuniones y que meses después no se parece en nada a lo que el cliente espera.&lt;/p&gt;

&lt;p&gt;Y para iterar es fundamental poder refactorizar, poder publicar cambios con un comando y dar marcha atrás con otro, tener tests de regresión automatizados que nos aseguren que en cada iteración no perdemos funcionalidad anterior. Todo eso son herramientas que se asume que son de implementación, pero que son fundamentales para poder tener un diseño flexible y una arquitectura escalable. No importa lo bien ideada que esté tu arquitectura, si no puedes refactorizar se va a enquistar. No importa lo flexible que sean tus clases, si no puedes dividirlas irán acumulando dependencias y deuda técnica hasta que sean una bola indigerible e insondable que nadie quiere tocar.&lt;/p&gt;

&lt;p&gt;El análisis y el diseño no es una parte previa al desarrollo, es necesariamente parte del desarrollo y sin conocimiento del problema y del contexto en el que se encuentra &lt;a href=&quot;https://www.linkedin.com/pulse/hard-thing-software-development-jesse-watson?__s=fotpfppvyfawf44bmqhj&quot;&gt;serás un desarrollador menos valorado&lt;/a&gt; y no podrás hacer un buen trabajo. El desarrollo de software no es simplemente apilar líneas de código como el que apila ladrillos, requiere un esfuerzo creativo y tomar muchas decisiones sobre como afrontar cada problema y cómo afectará cada decisión a largo plazo.&lt;/p&gt;

&lt;p&gt;Desarrollar software tampoco es como construir edificios o coches en el sentido de que o hay una cadena de montaje que cueste millones parar ni un enorme bloque de hormigón que no se pueda mover. No existe una forma concreta de hacer las cosas, no porque no exista, sino porque &lt;strong&gt;en eso es en lo que somos mejores: cada vez que encontramos una buena metodología o una un buen algoritmo convertimos esas partes en librerías, frameworks, automatismos, etc para poder reutilizarlo y no tener que preocuparnos más por eso&lt;/strong&gt;. Lo convertimos en un &lt;em&gt;comodity&lt;/em&gt; y pasamos al problema siguiente. Nunca habrá una cadena de montaje porque las partes que se pueden automatizar son asimiladas sobre capas de arquitecturas y lenguajes y el desarrollador siempre se encarga de resolver problemas &lt;em&gt;“encima”&lt;/em&gt; de esas capas. Nadie se preocupa hoy en día del protocolo TCP/IP al hacer una web.&lt;/p&gt;

&lt;p&gt;El software es flexible, es reutilizable, es portable y es caduco. No podemos poner de ejemplo los planos de un edificio porque en nuestro caso los usuarios vendrán y querrán mover la puerta de entrada, conectar la segunda planta con la sexta mediante un pasillo (no, un ascensor no, un pasillo), cambiar el tamaño del ascensor mientras está en uso y usar la piscina como pista de padel porque resulta que las piscinas ya no se llevan. Todo eso en el primer mes de uso.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;El software cambia muy rápido&lt;/strong&gt;, cambia constantemente y toda la teoría detrás del ciclo de vida en cascada está bien para desarrollar standards, para desarrollar hardware o para otro tipo de producto no moldeable, pero no para la mayoría del software.&lt;/p&gt;

&lt;p&gt;Dicho todo esto, sigo pensando que &lt;strong&gt;el diseño y el análisis tienen su lugar en el desarrollo de software, pero no como una disciplina separada de la implementación, sino como una forma de mantener, mejorar y evaluar el código&lt;/strong&gt;, de decidir dónde merece la pena gastar algo de tiempo en refactorizar, dónde hay que dividir un módulo o cómo organizar una arquitectura grande de forma que el trabajo se pueda dividir fácilmente. &lt;strong&gt;El eterno elefante en la habitación que no quieren ver los que defienden esa separación es que el único nivel lo suficientemente detallado para especificar qué debe hacer la máquina es el código&lt;/strong&gt;. Las herramientas de diseño, los gráficos, las especificaciones pueden darnos una falsa sansación de que estamos especificando el problema, pero aún no es posible especificarlo lo suficiente como para que la implementación sea trivial (¡Entonces no haría falta implementar!) y al final, el diseño inicial no es más que un corsé de otra talla que tenemos que desmontar por completo y volver a montar para que se adapte a nuestro producto, nuestro cliente y nuestro equipo.&lt;/p&gt;

&lt;p&gt;Esto no es algo que diga solo yo aquí, es algo que han dicho otros ingenieros y divulgadores mucho más sabios y experimentados que yo. Solo repito sus palabras a modo de resumen personal. Y por si alguien ahí sigue pensando que la arquitectura en cascada es una buena idea y no cree que yo tenga ninguna autoridad en el tema (tiene razón en esa última parte), termino con algunos enlaces mucho más interesantes e instructivos que mi opinión personal:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf&quot;&gt;Martin Fowler: Who needs architects&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.martinfowler.com/articles/designDead.html&quot;&gt;Martin Fowler: Is Design Dead?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.ibm.com/developerworks/java/library/j-eaed1/index.html&quot;&gt;Neal Ford: Investigating Architecture and design&lt;/a&gt;*&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://drive.google.com/file/d/0B8ZX1RoWHuiJandXOHRSSG1BV1U/view&quot;&gt;Michael Feathers: Emergent Optimization in Test Driven Design&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>¿Por qué el internet de las cosas (IoT) es tan difícil?</title>
   <link href="http://juanmirod.github.io/2017/04/29/porque-iot-es-dificil.html"/>
   <updated>2017-04-29T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/04/29/porque-iot-es-dificil</id>
   <content type="html">&lt;p&gt;Se lleva hablando del internet de las cosas (a partir de ahora Iot, por las siglas en inglés) desde que yo estaba en la facultad, hace ya como una década. Ya entonces las aplicaciones de domótica eran parecidas a las de ahora. Salvo alguna escepción como los nuevos asistentes tipo Alexa y Google Home, la tecnología ya permitía controlar las persianas, la calefacción, las luces, el hilo musical y electrodomésticos como la cafetera, la lavadora o la secadora.&lt;/p&gt;

&lt;p&gt;Es cierto que toda la tecnología electrócnica se ha abaratado mucho desde entonces. Las cámaras y sensores de todo tipo son mucho más baratos ahora gracias a los smartphones y al cambio que han supuesto en toda la industria. Pero aun así el internet de las cosas no termina de despegar. Se sigue hablando de él en futuro y nadie tiene del todo claro a qué se refiere.&lt;/p&gt;

&lt;p&gt;En un término que engloba muchas cosas, domótica, automatización, sistemas de localización, seguridad… pero a la vez en un mundo hiperconectado y lleno de aplicaciones que pueden hacer muchas de esas funciones su utilidad se diluye un poco.&lt;/p&gt;

&lt;p&gt;El problema también, a veces, es que nos lo quieren meter con calzador, sin saber muy bien donde.&lt;/p&gt;

&lt;p&gt;Muchas veces la automatización es útil y tiene un uso claro: los toldos con sensores de lluvia, viento y temperatura que pueden programarse para extenderse cuando hace calor pero recogerse si llueve o hace viento son un ejemplo de un uso concreto y útil de domótica que se puede implantar fácilmente.&lt;/p&gt;

&lt;p&gt;Pero muchas veces veo repetido otro patrón, el de cuando le hablas a alguien las “ventajas” del internet de las cosas y surgen más pegas que emoción:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;¡Podrás hacer la lista de la compra en el frigoríco!&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;¿Eso no es un poco incómodo?¿No puedo hacerla en el móvil y ya está?&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;No necesitarás llaves porque la puerta de casa te reconocerá.&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;¿Y si un día va un familiar a mi casa y yo no estoy? ¿Cómo le digo a mi puerta que lo deje entrar?&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Puedes hablarle a tu móvil.&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Pero si es mucho más rápido darle yo a llamar.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Con este dispositivo y esta app puedes encender y apagar cualquier luz de la casa desde el móvil.&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Ah, ¿Y eso para qué?&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Podrás programar la cafetera para que te prepare el café justo antes de levantarte.&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;¿Pero antes me tendré que preocupar de dejarla con el depósito de café y el de agua llenos no…?&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Un ejemplo muy palpable del fracaso del Iot antes de empezar son las luces con detector de movimiento. En realidad el invento no es un fracaso en sí, es un sistema muy útil y que permite ahorrar mucha energía. &lt;strong&gt;El fracaso del Iot es el de su implantación.&lt;/strong&gt; Me trataré de explicar con un ejemplo:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Las luces con dector de movimiento son una realidad en cientos de sitios, desde aseos públicos, lugares comunes en resicencias y oficinas, hospitales, etc. En general cualquier lugar de paso que no necesite estar todo el tiempo iluminado se puede beneficiar de este sistema: pones un detector de movimiento y sólo enciendes la luz si el sistema detecta que hay alguien, ¡Hasta te puedes ahorrar los interruptores! En teoría todo son ganancias.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pero ¿Qué pasa si el tiempo que le programamos es muy pequeño? ¿Quién no se ha quedado a oscuras en un baño público? ¿qué pasa cuando el detector se estropea? Antes, en lugares comunes los interruptores solían estar duplicados (al principio y al final de una escalera o pasillo, nada más entrar al portal y junto al ascensor, etc) pero ahora si el detector falla el sistema se queda ciego en toda esa zona y lo más seguro es que nos quedemos a oscuras hasta que lo arreglemos.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Con un par de ejemplos más de andar por casa:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;En mi portal el detector tiene muy poco tiempo programado, y siempre se apaga la luz cuando estás esperando el ascensor, con lo que tienes que estar moviendo los brazos como un imbécil para que vuelva la luz o disfrutar del momento de paz y darle un susto al vecino cuando sale del ascensor. Además, al constructor no se le ocurrió que la gente podía tomar las escaleras y no hay interruptor ni detector en el primer tramo, con lo que tienes que subir hasta el primer piso (donde está el primer interruptor) a oscuras.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Algo parecido me pasa en la oficina, donde los detectores también están puestos en el rellano del ascensor, con lo que si coges las escaleras hay un tramo en el que no tienes luz, hasta que llegas al siguiente rellano y se enciende la luz de ese piso…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Y es que ese es el problema del Iot, un montón de problemas de usabilidad que ya estaban resueltos cambian y hay que volver a pensarlos y diseñarlos, y como es normal, no sale bien a la primera.&lt;/p&gt;

&lt;p&gt;Estoy convencido de que poco a poco asistentes como Alexa o facilidades a la hora de hacer la lista de la compra o controlar la economía doméstica irán implantándose de forma general, pero el iot es un problema tan difícil de solventar como la robótica: intentar que un dispositivo electrónico se adapte al mundo real y a todas sus variaciones no es fácil, y todavía nos quedan muchos años de quedarnos a oscuras en mitad de una escalera.&lt;/p&gt;

&lt;p&gt;Un divertido video sobre esta problemática com muchos más ejemplos de los quebraderos de cabeza del Iot:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/S7JUMT66VXo?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&amp;lt;/iframe
&lt;/iframe&gt;
</content>
 </entry>
 
 <entry>
   <title>No ames la tecnología, ama tu oficio</title>
   <link href="http://juanmirod.github.io/2017/02/24/adora-tu-oficio.html"/>
   <updated>2017-02-24T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/02/24/adora-tu-oficio</id>
   <content type="html">&lt;p&gt;Ultimamente he estado reflexionando sobre lo que hace que me sienta bien en el trabajo y me interese más cada día en aprender y en seguir mejorando.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Por un lado el trabajo de desarrollador es un trabajo realmente privilegiado:&lt;/strong&gt; trabajo de oficina en lugares normalmente bien acondicionados, a veces incluso con café o una cocina a nuestra disposición, donde el mayor riesgo que corremos es el de la tendinitis del ratón o la vista cansada.&lt;/p&gt;

&lt;p&gt;Aunque eso no hace el trabajo divertido. Sí, puedes sentirte afortunado, pero no &lt;em&gt;emociona&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;En realidad, el día a día es bastante estático: Estás ocho horas diarias sentado delante del ordenador, probablemente más, de vez en cuando tienes alguna reunión o conferencia y puedes interactuar con otras personas, pero la mayor parte del tiempo solo eres tú, el código y la documentación de las X herramientas, frameworks, lenguajes, bases de datos y demás software y/o hardware que estés utilizando.&lt;/p&gt;

&lt;p&gt;Por otro lado, es habitual escuchar a los desarrolladores quejarse. Nos quejamos de los jefes, de la gestión del proyecto, de los clientes, de los diseñadores, de QA, de los demás desarrolladores, etc.&lt;/p&gt;

&lt;p&gt;Muchas páginas se han escrito sobre la frustración del programador. La frustración con las herramientas, con el lenguaje, con la metodología en cascada, con las metodologías ágiles… Que si en mi empresa usamos Angular y a mí me gustaría usar React, que si trabajamos con Java y a mí me gusta Python, que si indentar con tabs o con espacios, que si SCRUM no vale para nada, que si este código no hay quien lo entienda. Parece que nada nos vale. O bien somos muy exigentes o no lo estamos enfocando bien, y yo me decantaría por lo segundo.&lt;/p&gt;

&lt;p&gt;No digo que todas esas quejas sean inventadas o ilegítimas. Pero si lo piensas, son tonterías, cosas sin importancia. No deberían preocuparnos, y además normalmente no está en nuestra mano cambiarlas. Siempre habrá aspectos que mejorar y cosas que se podrían haber hecho diferente. Pero creo que en lugar de centrarnos en el último framework o lenguaje de moda, debemos centrarnos en mejorar nuestro código y nuestro trabajo cada día.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Si cada día te pones delante del código/software/producto y te planteas ¿Cómo podría hacerlo mejor? ¿Cómo podría hacerlo más rápido/legible/seguro/automático? entonces todo lo demás empieza a parecer menos importante.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tenemos delante un problema que podemos y debemos atacar sin depender de nadie: &lt;strong&gt;nuestro código&lt;/strong&gt;. Muchas veces no podemos elegir el lenguaje, las APIs que usamos o la base de datos con la que interactuamos. Pero sí tenemos control sobre el código que escribimos y mantenemos. Ese es nuestro trabajo y es ahí donde podemos centrarnos en mejorar. Además somos una de las pocas profesiones donde tenemos control directo sobre las herramientas que utilizamos y sobre lo que producimos, no debemos olvidar que nuestro oficio es muy artesanal todavía en ese sentido y podemos aprovecharnos de esa ventaja.&lt;/p&gt;

&lt;p&gt;¿Probar tu código es lento porque tienes que pasar por X pasos hasta llegar a lo que tú has escrito? Tal vez si el código estuviera en un módulo independiente y pudieras escribir unos tests la experiencia sería completamente diferente.&lt;/p&gt;

&lt;p&gt;¿La aplicación es lenta y siempre tienes que esperar X segundos a que se inicie? Tal vez puedes echar un ojo al código de arranque para optimizarlo.&lt;/p&gt;

&lt;p&gt;¿No te gusta trabajar con la API/BBDD/librería de terceros? A lo mejor puedas hacer un interfaz o una fachada que haga que no te tengas que preocupar más de ese problema.&lt;/p&gt;

&lt;p&gt;¿Te da pánico cada vez que tienes que cambiar algo en el código porque no sabes si estás rompiendo otra cosa? Toca escribir unos tests de regresión…&lt;/p&gt;

&lt;p&gt;En definitiva: ataca los problemas que están a tu alcance, convierte las incomodidades en retos. &lt;strong&gt;Reduce la fricción en tu trabajo día a día. ¡Automatiza todo lo que puedas!&lt;/strong&gt; La tecnología es una herramienta, no te enamores de cada nuevo lenguaje o de cada nuevo IDE, enamórate de tu capacidad para crear y modificar tus herramientas y tu producto. Estarás más motivado, mejorarás como desarrollador y serás más productivo.&lt;/p&gt;

&lt;p&gt;Es muy fácil caer en la tentación de hacer lo justo para que funcione, de meter unas cuantas líneas de código con calzador aquí y allí para arreglar el bug o para añadir esa funcionalidad que corre tanta prisa. Pero cuando eso ocurra, piensa de nuevo en los problemas de arriba. &lt;strong&gt;Nosotros creamos o reducimos nuestra deuda técnica con cada día de desarrollo&lt;/strong&gt;. Está en tu mano convertir tu código y tu flujo de trabajo en un placer o en un martirio para ti y para los demás desarrolladores de tu equipo. &lt;strong&gt;Ten valor y toma el control de tu oficio, haz de tu trabajo un placer&lt;/strong&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Introducción a la programación en JavaScript</title>
   <link href="http://juanmirod.github.io/2017/01/02/introduccion-a-la-programacion.html"/>
   <updated>2017-01-02T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2017/01/02/introduccion-a-la-programacion</id>
   <content type="html">&lt;p&gt;¿Quieres aprender a programar? ¿Has oído hablar de JavaScript y te gustaría empezar por ahí pero no sabes por dónde empezar? Este es un curso básico de programación utilizando JavaScript. No son necesarios conocimientos previos, aunque saber inglés siempre es una ventaja ya que la mayoría de la documentación está en ese idioma.&lt;/p&gt;

&lt;p&gt;// …existing code…&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Promesas en Javascript</title>
   <link href="http://juanmirod.github.io/2016/11/25/promesas-en-javascript.html"/>
   <updated>2016-11-25T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/11/25/promesas-en-javascript</id>
   <content type="html">&lt;p&gt;El objeto Promise es ya un &lt;a href=&quot;http://www.ecma-international.org/ecma-262/6.0/#sec-promise-objects&quot;&gt;standard de ES2015&lt;/a&gt; y puede utilizarse en la mayoría de los navegadores. Para poder utilizarlo y seguir soportando IE (esa carga que todos los desarrolladores web llevamos a cuestas) existe un &lt;a href=&quot;https://github.com/taylorhakes/promise-polyfill&quot;&gt;polyfill&lt;/a&gt; que apenas ocupa 1kb.&lt;/p&gt;

&lt;p&gt;En esos enlaces puedes encontrar lo que es una Promesa y cómo funciona, pero las especificaciones no son precisamente fáciles de leer. Personalmente encuentro mucho más útil aprender con metáforas y ejemplos que muestren cómo se utiliza un concepto concreto.&lt;/p&gt;

&lt;h2 id=&quot;qué-es-una-promesa-y-cómo-se-utiliza&quot;&gt;¿Qué es una promesa y cómo se utiliza?&lt;/h2&gt;

&lt;p&gt;Decimos que una promesa es como un recibo que nos dan de un pedido. Sabemos que va a tardar X, y que no lo tenemos justo al pagar, pero el recibo y su localizador nos aseguran que tendremos el producto en el futuro.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/img/wait_number.jpg&quot; alt=&quot;Imagen de un ticket de una cola de espera&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Poniéndonos algo más técnicos, una promesa es un objeto que encapsula una operación asíncrona. La operación asíncrona (una llamada AJAX, un evento, una llamada a una función programada para el futuro) tiene una duración indeterminada, pero al crear una promesa obtenemos inmediatamente un objeto con el que podemos trabajar. Es decir:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  
  &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello World!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Promise { ... }&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// promise es un objeto, no tenemos que esperar para poder usarlo!&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En este punto la variable promise es un objeto y podemos operar con él. Hasta dentro de 10 segundos no se establecerá su valor y no contendrá la cadena ‘Hello world!’ pero podemos seguir trabajando con ella como si si que fuera así.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.then&lt;/code&gt; es un método de la promesa que acepta una función, cuando la promesa se resuelve, llama a la función que le pasamos a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.then&lt;/code&gt; pasándole como parámetro lo que le pasáramos a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resolve&lt;/code&gt;. En realidad, le estamos pasando a &lt;em&gt;.then&lt;/em&gt; la función  &lt;em&gt;resolve&lt;/em&gt;. Veamos como se haría en el ejemplo anterior:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// &apos;Hello World!&apos;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Así dicho parece que lo que estamos haciendo es complicar las cosas, pero las promesas tienen dos ventajas principales:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Nos devuelven el control.&lt;/strong&gt; Gracias a las promesas, mantenemos control sobre la ejecución de nuestro programa, que antes delegábamos en una llamada asíncrona que podía o no terminar. Ahora con las promesas podemos operar independientemente de lo que pase con la llamada asíncrona. Además, las promesas tienen la gran ventaja de que si el código lanza una excepción dentro de la Promesa, ésta la capturará y la devolverá convenientemente con la función ‘catch’.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Las promesas se pueden encadenar.&lt;/strong&gt; Podemos hacer que la ejecución de una promesa dependa de otra, o esperar a que todo un grupo de promesas se resuelvan. Esto hace que el código sea mucho menos engorroso y mucho más fácil de leer y mantener.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;vamos-a-ver-varios-ejemplos-prácticos-y-su-implementación-para-aclarar-conceptos&quot;&gt;Vamos a ver varios ejemplos prácticos y su implementación para aclarar conceptos.&lt;/h2&gt;

&lt;p&gt;El ejemplo típico de utilización de una promesa es una llamada AJAX. Si has usado jQuery, la sintaxis es muy similar, y de hecho en jQuery 3.0 han modificado el código para que se comporte como una Promesa, ya que antes &lt;a href=&quot;https://blog.domenic.me/youre-missing-the-point-of-promises/&quot;&gt;había algunas diferencias&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;http://...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// operaciones con data&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// muestra el error&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pero si no necesitamos jQuery para nada más, a lo mejor no queremos incluirl en nuestro proyecto sólo para esto. Por suerte, los navegadores ya comienzan a soportar la función &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API&quot;&gt;‘fetch’&lt;/a&gt;, que devuelve una promesa y funciona de forma parecida a la función ajax de jQuery, pero usando la terminología estandard:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;http://...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// operaciones con response&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// muestra el error&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Estas funciones sólo son válidas para peticiones AJAX, pero las promesas no se restringen solo a esto. Podemos usarlas para cualquier operación no síncrona. Podemos usarlas para funciones que queremos ejecutar en el futuro como en el primer ejemplo, o para encapsular la ejecución de eventos, controlar procesos que tardan cierto tiempo en ejecutarse, peticiones a la cache, etc.&lt;/p&gt;

&lt;p&gt;Un ejemplo diferente de cómo utilizar una promesa es utilizarlas para ejecutar nuestra aplicación cuando el DOM se ha cargado y está listo.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// Resuelve la promesa cuando el DOM está listo&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;readystatechange&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readyState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;loading&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Aquí podemos hacer cosas con el DOM&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ese es un ejemplo de un evento que sabemos que ocurrirá solo una vez y que podemos capturar en una promesa. Y lo de solo una vez es importante porque &lt;strong&gt;una vez la promesa toma un valor, no se modificará. Se dice que la promesa se ha cumplido, resuelto o establecido&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Además de &lt;em&gt;‘resolverse’&lt;/em&gt; las promesas pueden &lt;em&gt;‘denegarse’&lt;/em&gt;. Para denegarlas, llamaremos a la segunda función que recibimos como parámetro que normalmente recibe el nombre de ‘reject’:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  
  &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello World!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Something went wrong!!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sayHello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ERROR: &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// &apos;ERROR: Something went wrong!&apos;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cuando una promesa es rechazada, la ejecución saltará directamente al primer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.catch&lt;/code&gt; que encuentre, saltándose el/los then (luego veremos que puede hacer varios) que haya delante.&lt;/p&gt;

&lt;p&gt;Pero como una promesa una vez tome un valor no se modificará, si se resuelve y algo más tarde tratamos de denegarla, la promesa ignorará la llamada a &lt;em&gt;‘reject’&lt;/em&gt; y mantendrá el valor con el que se resolvió. Esto hace que podamos añadir un tiempo de expiración a nuestras promesas. Por ejemplo, para una petición o un evento que esperamos que se ejecute antes de un tiempo determinado, podríamos añadir un tiempo máximo por el que esperar a que se descargue una imagen o un script y si se supera ese tiempo, tomarlo como un error:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;onload&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;onerror&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;There was an error&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// timeout en 1s&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Something must be wrong, try again or fallback to something else&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Imagen cargada correctamente&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Hubo un error, mostrar mensaje o cargar imagen por defecto...&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lo importante en este ejemplo es que &lt;strong&gt;hemos encapsulado todo el manejo de los eventos del elemento dentro de la promesa&lt;/strong&gt;, y de cara al exterior ahora solo tenemos una función que devuelve una promesa, lo que simplifica enormente el código y mejora su reusabilidad y legibilidad.&lt;/p&gt;

&lt;p&gt;En el ejemplo anterior estamos denegando la promesa ante errores o expiración del tiempo de espera. Pero en lugar de denegar la promesa podríamos lanzar una excepción y el resultado sería el mismo: la promesa capturaría la excepción y se denegaría. Esto puede usarse con funciones que puedan causar excepciones, como lectura de ficheros o de base de datos. Hay un buen ejemplo de esto en &lt;a href=&quot;http://bluebirdjs.com/docs/why-promises.html&quot;&gt;la documentación de Bluebird&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readFileAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;file.json&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SyntaxError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;invalid json in file&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;unable to read file&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Otra de las grandes ventajas de las promesas que aún no hemos probado, es la de encadenarlas. &lt;strong&gt;Decimos que las promesas son ‘thenables’, es decir que se les puede poner un ‘then’ detrás y pasarán el resultado con el que se han resuelto a la función que le pasemos al then.&lt;/strong&gt; De esta forma podemos hacer que la ejecución de una promesa dependa del resultado de otra, sin necesidad de anidarlas:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;http://search&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getFirstVideo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Hacer cosas con results&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;http://...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;showVideoData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// result2 depende de result1 pero la estructura del código es lineal :)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Esto también ayuda a simplificar el código y sobre todo a librarnos de la terrible pirámide de callbacks que se genera al tener que anidar las llamadas asíncronas en javascript para poder acceder al valor de la llamada anterior.&lt;/p&gt;

&lt;p&gt;También podemos hacer que una promesa dependa de que se terminen varias promesas que se ejecutaron paralelamente:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promise1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arrayOfResults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;La función all, &lt;strong&gt;además de devolver todos los resultados en orden independientemente de cuándo se resuelvan las promesas, fallará si alguna de ellas falla&lt;/strong&gt;, con lo que nuestro código sólo se ejecutará si tenemos los resultados de todas las promesas.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.all&lt;/code&gt; ejecuta todas las promesas de forma paralela, no en secuencia, es decir, es para ejecutar un montón de promesas que no dependen de las demás para ejecutarse, como por ejemplo descargar información meteorológica de varias ciudades a la vez para compararlas.&lt;/p&gt;

&lt;p&gt;Además de &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.all&lt;/code&gt;, las promesas de ES6 incluyen la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.race&lt;/code&gt;. &lt;strong&gt;Race ejecuta un array de promesas como .all pero el then se ejecutará en el momento en el que la primera promesa se resuelva, sin esperar a las demás&lt;/strong&gt;. Como su nombre indica, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.race&lt;/code&gt; es un una carrera para quedarnos con la promesa que resuelva más rápido. Esto nos puede servir para consultar varios servicios a la vez y quedarnos con el primer resultado que llegue. En el ejemplo del tiempo, podríamos consultar el tiempo para la misma cuidad en diferentes APIs y devolver al usuario el primer resultado, obteniendo así el resultado más rápido posible.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;p1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;p2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;race&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;p2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// &quot;two&quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Los dos se resuelven, pero p2 es más rápida&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Estas funciones pueden crearse gracias a que, como comentaba antes, las Promesas encapsulan operaciones asíncronas devolviéndonos siempre el mismo interface, dándonos una forma fácil de manipularlas y agruparlas.&lt;/p&gt;

&lt;p&gt;Tanto es así, que, con algunas modificaciones, las promesas podrían ser una mónada, en &lt;a href=&quot;https://github.com/promises-aplus/promises-spec/issues/94&quot;&gt;este hilo de github&lt;/a&gt; se puede seguir una interesante conversación entre varios desarrolladores muy conocidos sobre ese tema. Cuando las promesas estaban en proceso de especificación en el lenguaje, algunos programadores del mundo de la programación funcional se quejaron de que no eran “correctas”, no permitían las operaciones de composición que podrían permitir y así los desarrolladores de JavaScript perdíamos un gran potencial. Recientemente André Stalz ha renovado el debate &lt;a href=&quot;https://staltz.com/promises-are-not-neutral-enough.html&quot;&gt;en su blog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aun así, la solución de las promesas de Javascript nos da un interface que es cási una mónada y sobre el que también podemos operar, aunque no sea de forma tan genérica, &lt;a href=&quot;https://medium.com/@jamiedixon/promises-and-arrays-are-the-same-5ea68a4d769b#.ogdbn4l4s&quot;&gt;con operaciones como map/filter/reduce&lt;/a&gt;, esto es lo que hace &lt;a href=&quot;http://bluebirdjs.com/docs/api-reference.html&quot;&gt;Bluebird&lt;/a&gt;, dándonos todo el repertorio de operaciones que podemos hacer con promesas, lo que resulta muy útil cuando todas nuestras librerías devuelven promesas y podemos manejarlas a alto nivel. Además, si nuestra librería no está escrita con promesas, sino con el estilo de callbacks de node, pero queremos aprovechar las ventajas de las promesas, Bluebird nos da una función para convertir las funciones que usan callbacks a promesas: &lt;a href=&quot;http://bluebirdjs.com/docs/api/promise.promisify.html&quot;&gt;promisify&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;ACTUALIZACIÓN: Node también incluye una función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;promisify&lt;/code&gt; &lt;a href=&quot;https://nodejs.org/api/util.html#util_util_promisify_original&quot;&gt;desde la versión 8&lt;/a&gt;, con lo que ya no es necesario usar Bluebird para esto.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;patrones-útiles&quot;&gt;Patrones útiles&lt;/h2&gt;

&lt;p&gt;Cuando llevas un tiempo usando promesas de forma regular, te das cuenta de que hay ciertos patrones de código que se repiten.&lt;/p&gt;

&lt;h3 id=&quot;composiciónflujo-de-promesas&quot;&gt;Composición/flujo de promesas&lt;/h3&gt;

&lt;p&gt;Una de las coas que ocurre cuando usas promesas es que acabas teniendo que usarlas para todo. Si no pierdes las ventajas de la captura de errores y el encapsulamiento. Esto es debido al problema que hemos comentado antes de que las promesas son muy dogmáticas en su comportamiento y te obligan a moldear tu código para utilizarlas. Todo esto para decir que al usar promesas es habitual tener código que depende de una ejecución secuencial de promesas:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;promesa1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promesa2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promesa3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promesa4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promesa5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Es algo que suele ocurrir cuando tenemos que preparar algún tipo de entorno, como un entorno de testing o la inicialización de la app o el provisioning de una base de datos y necesitamos ejecutar una serie de acciones de manera secuencial. Puedes ver un ejemplo con código real en &lt;a href=&quot;https://github.com/couchbaselabs/devguide-examples/blob/master/nodejs/subdocES6.js#L19&quot;&gt;este repositorio de couchbase&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;// Run the example&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;verifyNodejsVersion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeInitial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lookupEntireDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;subdocItemLookupTwoFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;subdocArrayAdd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lookupEntireDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;subdocArrayManipulation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;subDocumentItemLookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;subdocArrayRemoveItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;subDocumentItemLookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ERR:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En este caso, el código ejecuta una serie de acciones sobre la base de datos y sale, como un proceso por lotes, aunque es solo un ejemplo de uso.&lt;/p&gt;

&lt;p&gt;Seguramente, ver ese ejemplo hace que algo no te parezca bien. Aunque encadenar las funciones de esta forma es lineal y muy funcional y nos permite tener control sobre las excepciones, este código no es DRY, hay algo que se repite en casi todas las líneas: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.then(&lt;/code&gt;. Es ver algo así y a la mayoría se nos pone la piel de gallina, hay algo que no está bien en tener que repetirse tanto. Y tenemos razón, lo que ocurre es que el &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.then&lt;/code&gt; tiene un comportamiento muy peculiar que hace que tengamos que usarlo así y no podamos componerlo directamente. Lo ideal, lo que está pidiendo este código, sería poder hacer:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;verifyNodejsVersion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;storeInitial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;lookupEntireDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subdocItemLookupTwoFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subdocArrayAdd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;lookupEntireDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subdocArrayManipulation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subDocumentItemLookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subdocArrayRemoveItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subDocumentItemLookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ERR:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ERROR...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Si te estás preguntándo qué hace la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipe&lt;/code&gt;, puedes verlo en &lt;a href=&quot;http://juanmirod.github.io/2017/06/16/introduccion-programacion-funcional-javascript.html&quot;&gt;este artículo sobre programación funcional&lt;/a&gt; Pero sigue leyendo y lo aclaro en un momento con la solución.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pero no podemos hacer eso con las promesas. ¡&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipe&lt;/code&gt; no llama a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.then&lt;/code&gt;! Esa era la principal queja de los programadores funcionales cuando querían cambiar la especificación de las promesas de JavaScript. No podemos usar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipe&lt;/code&gt;, ni &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compose&lt;/code&gt;, ni &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt;, ni &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fold&lt;/code&gt;, ni ninguna de todas esas herramientas funcionales tal y como están.&lt;/p&gt;

&lt;p&gt;Pero, aunque esta no sea una situación ideal, y algunos hayan decidido hacer sus propias promesas que encajen dentro del resto de la programación funcional, lo que sí que podemos hacer es nuestra propia función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipePromises&lt;/code&gt;. Y además no es nada del otro mundo:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pipePromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promisesFunctions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promisesFunctions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastPromise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lastPromise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
    &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Esta función encadena las promesas usando &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.then&lt;/code&gt; y pasando el resultado de una a la siguiente. Con esta función podríamos encadenar las promesas sin repetir los &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.then&lt;/code&gt; y manteniendo la funcionalidad del primer código:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;pipePromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;verifyNodejsVersion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;storeInitial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;lookupEntireDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subdocItemLookupTwoFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subdocArrayAdd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;lookupEntireDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subdocArrayManipulation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subDocumentItemLookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subdocArrayRemoveItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;subDocumentItemLookup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ERR:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Puedes comprobar que funciona con &lt;a href=&quot;https://jsfiddle.net/juanmirod/wr5gsm5x/&quot;&gt;este fiddle&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pipePromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promisesFunctions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promisesFunctions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastPromise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lastPromise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; 
    &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promiseInc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;pipePromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promiseInc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;promiseInc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;promiseInc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;promiseInc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;promiseInc&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// 5&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;el-árbol-de-promesas&quot;&gt;El árbol de promesas&lt;/h3&gt;

&lt;p&gt;El problema más común con las promesas es el mismo que con los callbacks: en lugar de un “árbol de navidad” de callbacks podemos acabar creando un árbol de navidad de promesas.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;promiseA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functionB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingFancy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Esto ocurre porque la función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doSomethingFancy&lt;/code&gt; necesita los valores devueltos por las dos promesas y functionB también necesita el valor de la primera promesa. Si estamos usando Bluebird, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;join&lt;/code&gt; puede ayudarnos con esto, pero si no queremos aprender otro API más o añadir otra dependencia a nuestro proyecto, hay varias formas de solucionar el problema con las promesas nativas de &lt;strong&gt;es6&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Utilizando variables en el ámbito superior.&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sample&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promiseA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functionB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingFancy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Simplemente copiamos los resultados de las promesas en variables accesibles por todas las funciones por estar en un ámbito superior. El código vuelve a ser lineal y solo hemos tenido que añadir una variable, bastante limpio y fácil de leer, suele ser mi primera opción para este problema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Otra solución utilizando ‘.all’:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;promiseA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functionB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingFancy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;De esta forma no necesitamos crear una variable externa, la funcion ‘.all’ acepta valores y promesas y nos devuelve un array con todos los resultados. La sintaxis gracias a &lt;strong&gt;es6&lt;/strong&gt; es bastante legible aunque algo menos que la anterior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Utilizando una función auxiliar:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;joinPromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;functionA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functionAB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functionB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functionAB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;promiseA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;joinPromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;functionB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingFancy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En este caso hemos creado una pequeña función que nos ayuda a pasar los parámetros, se podría generalizar para N argumentos, pero así queda más fácil de leer y se entiende mejor el ejemplo (ver el final del artículo para una generalización parecida). De hecho, utilizando la notación ‘pointFree’ podemos dejar el ejemplo incluso más conciso:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;joinPromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;functionA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functionAB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functionB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;functionAB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resultB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;promiseA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;joinPromises&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;functionB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingFancy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;anti-patrones-al-utilizar-promesas&quot;&gt;Anti-patrones al utilizar promesas&lt;/h2&gt;

&lt;p&gt;A la hora de usar promesas también hay que tener cuidado de no caer en algunas malas prácticas que harán que perdamos las ventajas de las promesas por el camino. Un ejemplo (fuente: taoofcode,ver algo más abajo) de un código que puede parecer correcto e incluso más legible según al tipo de código que estemos acostumbrado sería:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;anAsyncCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;somethingComplicated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Parece que lo estamos haciendo bien, pero en realidad estamos devolviendo la primera promesa en lugar del resultado del then, con lo que las excepciones que puedan provocarse y el propio resultado del then se perderán, esto puede comprobarse con el siguiente ejemplo (&lt;a href=&quot;https://jsfiddle.net/juanmirod/gscxwmcn/&quot;&gt;jsfiddle&lt;/a&gt;):&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;doSomethingAsync&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;somethingComplicated&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Error, too much complexity&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;anAsyncCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;somethingComplicated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;anAsyncCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;El catch no captura la excepción, además, si no se produjera la excepción, el resultado de ‘somethingComplicated’ se pierde porque no lo estamos devolviendo en el then.&lt;/p&gt;

&lt;p&gt;Veamos el ejemplo corregido (&lt;a href=&quot;https://jsfiddle.net/juanmirod/wp5981sz/&quot;&gt;jsfiddle&lt;/a&gt;):&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;doSomethingAsync&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;somethingComplicated&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Error, too much complexity&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;anAsyncCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;doSomethingAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;somethingComplicated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;anAsyncCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Con el nuevo código sí se captura la excepción. Además, si comentamos la línea del throw, el resultado por consola es 10 en lugar de 5, porque estamos obteniendo el resultado de ejecutar ‘somethingComplicated’ lo que, seguramente, era la intención de escribir el código de esta manera.&lt;/p&gt;

&lt;p&gt;Seguiré editando el artículo y añadiéndo ejemplos en cuanto pueda, pero mientras dejo un par de artículos sobre el tema: &lt;a href=&quot;http://bluebirdjs.com/docs/anti-patterns.html&quot;&gt;Bluebird - Anti-patterns&lt;/a&gt;, &lt;a href=&quot;https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html&quot;&gt;We have a problem with promises&lt;/a&gt; y &lt;a href=&quot;http://taoofcode.net/promise-anti-patterns/&quot;&gt;Promises anti-patterns en taoofcode&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusiones&quot;&gt;Conclusiones&lt;/h2&gt;

&lt;p&gt;La conclusión a todo esto: utiliza promesas para mejorar la legibilidad y fiabilidad de tu código y recuperar el control de la ejecución del código asíncrono. Este es un artículo largo, pero solo he dado un repaso superficial a las propiedades y usos de las promesas. Es importante aprender a usarlas correctamente, pero son una herramienta muy poderosa para mejorar tu código en JavaScript.&lt;/p&gt;

&lt;h2 id=&quot;material-para-ampliar&quot;&gt;Material para ampliar&lt;/h2&gt;

&lt;p&gt;Hay mucha documentación de calidad en Inglés y online sobre promesas, algunos enlaces de referencia son:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.udacity.com/course/javascript-promises--ud898&quot;&gt;Curso sobre promesas en Udacity&lt;/a&gt; Muy buen material y ejercicios para fijar los conocimientos, los cursos de Udacity son de los mejores cursos online que he probado.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://developers.google.com/web/fundamentals/getting-started/primers/promises#events_arent_always_the_best_way&quot;&gt;Javascript’s Promises: An Introduction&lt;/a&gt; Fantástica y extensa introducción a las promesas por Jake Archibald.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/getify/You-Dont-Know-JS/blob/master/async%20%26%20performance/ch3.md&quot;&gt;Capítulo You don’t know JS&lt;/a&gt; &lt;a href=&quot;https://twitter.com/getify&quot;&gt;@getify&lt;/a&gt; tiene todo un capítulo de uno de sus libros dedicado a las promesas. Como siempre contenido en profundidad e impecable, estos libros son de obligada referencia para cualquier desarrollador de JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Articulo en MDN&lt;/a&gt; La documentación de MDN sobre promesas, también en español.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>No hagas TDD (todavía)</title>
   <link href="http://juanmirod.github.io/2016/11/15/no-hagas-tdd.html"/>
   <updated>2016-11-15T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/11/15/no-hagas-tdd</id>
   <content type="html">&lt;p&gt;Llevo un tiempo tratando activamente de aprender a desarrollar usando TDD y la verdad, debo decir que, con muy poco éxito. No ha sido hasta hace poco que he comenzado a escribir tests más fácilmente y a entender el valor de escribir primero un test que falla para tener que escribir el código después.&lt;/p&gt;

&lt;p&gt;Creo que no seré el único con este problema y por eso quería compartirlo. Personalmente, después de mucho leer y ver videos de código en directo, tutoriales y conferencias sobre TDD, creo que el problema para muchos como yo es que quedemos correr antes de aprender a andar y claro, la experiencia es frustrante, nos damos contra un muro, y por eso la mayoría reniegan del TDD.&lt;/p&gt;

&lt;p&gt;Admitámoslo, primero queremos hacerlo porque los &lt;a href=&quot;https://www.youtube.com/watch?v=SSCzDykng4g&quot;&gt;chicos guays&lt;/a&gt; lo hacen. &lt;strong&gt;Bob Martin, Martin Fowler, Ken Beck, Gary Bernhardt, Toran Billups, DHH&lt;/strong&gt;, etc. Ellos son los que dan las conferencias, los que escriben los libros, y a todos nos gustaría estar en su lugar. Algunos tal vez penséis que hacen esas cosas por que ellos son más listos y por eso pueden hacer TDD, yo creo que es al revés, por que hacen TDD, por que hacen XP, porque conocen su profesión es por lo que tienen mejores resultados y parecen más listos.&lt;/p&gt;

&lt;p&gt;Pero el problema está en querer de la noche a la mañana escribir una aplicación como si fuera un live-streaming de uno de ellos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eso no va a funcionar.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Primero esos live streaming están preparados con antelación, repetidos varias veces, con toda la configuración a punto y con los problemas justos para que todo salga bien a la primera.&lt;/p&gt;

&lt;p&gt;Segundo y más importante, ¿Alguna vez has escrito un test para tu código? Si no sabes ni siquiera escribir un test ¿Cómo vas a hacerlo antes de empezar a programar?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Esta gente lleva escribiendo tests años.&lt;/strong&gt; Cuando comenzaron con TDD ya llevaban años escribiendo tests y conocían cómo poner todo en su lugar.&lt;/p&gt;

&lt;h3 id=&quot;tdd-es-una-extensión-de-eso&quot;&gt;TDD es una extensión de eso.&lt;/h3&gt;

&lt;p&gt;Cuando tienes una batería de tests y sabes cómo escribirlos, añadir un test que defina un nuevo requisito antes de escribir el código no parece tan difícil. De hecho si ahora algunos se plantean si el &lt;a href=&quot;http://martinfowler.com/articles/is-tdd-dead/&quot;&gt;TDD sigue sirviéndoles&lt;/a&gt;, es por que lo tienen totalmente asimilado.&lt;/p&gt;

&lt;p&gt;Por eso mi propuesta de hoy es que si aún no escribes tests &lt;strong&gt;NO HAGAS TDD&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Al menos no todavía.&lt;/p&gt;

&lt;p&gt;Empieza por añadir tests a tu proyecto actual. Configúralo para que sea fácil correr y escribir los tests, añade algunos tests para las cosas que sueles probar manualmente cuando haces un cambio y verás que mejoras el conocimiento de tu código y tu proyecto. Que descubres errores o simplemente hacks en el código que estabas dejando pasar pero que para que los tests funcionen tienes que arreglar.&lt;/p&gt;

&lt;p&gt;Comienza por lo que sea más fácil testear, algún módulo independiente o un servicio o librería que no tenga dependencias. Te garantizo que sólo con poder escribir dos o tres tests y poder ejecutarlos habrás aprendido muchísimo.&lt;/p&gt;

&lt;p&gt;Luego sigue desde ahí. Añade más tests para el resto de clases, añade un test cada vez que te encuentres probando algo manualmente. Añade un test cuando te reporten un bug, de forma que puedas reproducir el bug sin ir tener que seguir una serie de pasos manualmente hasta que salte.&lt;/p&gt;

&lt;p&gt;Cuando hagas todo eso en un par de proyectos, cuando te encuentres cómodo escribiendo tests y corriéndolos cada vez que modificas tu código para comprobar que no has roto nada, ya habrás ganado MUCHO en confianza sobre tus habilidades y tu código y el TDD no te parecerá tan lejano.&lt;/p&gt;

&lt;p&gt;Para mi es como un viaje, como un camino hacia una meta que es ser capaz de desarrollar con confianza de que lo que desarrollo funciona, se puede modificar y es legible y sensato para otros desarrolladores.&lt;/p&gt;

&lt;p&gt;Todo el mundo puede copiar y pegar, remendar y debuggear código hasta que tiene una maraña inexplicable que funciona pero es un suplicio para cualquiera que intenta modificarla o entederla. Pero solo algunos pueden llegar a dominar esta ciencia/arte. TDD es una de las técnicas que nos ayudan. Para mi, Extreme Programming es siempre el ejemplo, la meta, y contiene muchas más prácticas y recomendaciones que trataré de explorar en otros artículos.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Artículo de investigación sobre redes neuronales y procesamiento de imágenes</title>
   <link href="http://juanmirod.github.io/2016/07/15/articulo-investigacion-rrnn.html"/>
   <updated>2016-07-15T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/07/15/articulo-investigacion-rrnn</id>
   <content type="html">&lt;p&gt;En realidad es el primero y por ahora el único, pero quien sabe, a lo mejor algún día vendrán más…&lt;/p&gt;

&lt;p&gt;Es muy viejo, lo publiqué durante mi proyecto de fin de carrera y realmente lo hice porque mi director de proyecto se empeñó. Yo no sabía cómo iba eso de la investigación y realmente no me interesaba meter cabeza en la universidad, siempre me ha interesado más el +Mundo Real+ porque me gusta ver que lo que hago tiene aplicación directa y porque no me gustaban la burocracia y las jerarquías que inundan todas las instituciones que dependen del gobierno.&lt;/p&gt;

&lt;p&gt;Pero al final publicamos este artículo, sobre los tres algoritmos principales que implementé durante el proyecto de fin de carrera. Lo dejo aquí para guardarlo en algún sitio fácil de encontrar y mantener una reseña a él también a nivel personal.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/public/veredas_and_rodriguez_070206.pdf&quot;&gt;A self-organizing elastic map to measure the contour of skin pressure ulcers in digital images - Veredas and Rodriguez&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Conexiones persistentes en CodeIgniter</title>
   <link href="http://juanmirod.github.io/2016/06/26/conexiones-persistentes-codeigniter.html"/>
   <updated>2016-06-26T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/06/26/conexiones-persistentes-codeigniter</id>
   <content type="html">&lt;p&gt;Hace poco tuve un problema recurrente con el servidor que no terminaba de arreglar: en determinados picos de visitas a uno de los servidores que administro, uno de los cron jobs y alguna de las webs me devolvían el error de MySQL “Too many connections”. Este error es fácil de resolver si sabes dónde mirar, pero si no puede ser muy engañoso. Con una rápida búsqueda en Google puedes ver que todo el mundo te dice cómo aumentar el número de conexiones simultáneas, esto es, la variable global de MySQL: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max_connections&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ok, te conectas con tu usuario administrador a MySQL (tuve que buscarlo, pero lo encontré). Utilizas los nuevos comandos que has aprendido, a saber:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mysql&amp;gt; show processlist;  # muestra la lista de conexiones abiertas
mysql&amp;gt; set global variable max_connections=100;  # setea una variable global
mysql&amp;gt; select global variable max_connections # muestra el valor de la variable
mysql&amp;gt; show variables; # muestra todas las variables de mysql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Actualizas la variable (max_connections=100 o lo que quieras, cuidado con poner números grandes, que esto consume RAM…) La cambias en el fichero /etc/my.cnf por si reinicias el servicio que no te vuelva al valor anterior y listo!&lt;/p&gt;

&lt;p&gt;Bueno no…&lt;/p&gt;

&lt;p&gt;En esa búsqueda rápida todo el mundo también te decía que lo importante no es aumentar este número, este es el típico “Pan para hoy y hambre para mañana”. Lo que deberías hacer de verdad es tener cuidado con no dejar abiertas las conexiones en a mysql y no utilizar conexiones persistentes en PHP. Esto me quedó también bastante claro, pero como en estos proyectos usaba CodeIgniter, no pensé que eso fuera algo que se les hubiera escapado a los creadores del Framework.&lt;/p&gt;

&lt;p&gt;¡Pues resulta que sí! Si miráis en la documentación de Codeigniter, o en el fichero database.php, veréis que el modo persistente está activado por defecto, haciendo que todas las conexiones que realiza Codeigniter sean persistentes. No voy a entrar en por qué esto es así, pero la mayoría de las opiniones que leí decían que era una MALA IDEA tener conexiones persistentes si no estabas seguro de lo que estabas haciendo y lo hacías bien. Efectivamente, en mi caso, no eran necesarias, sino que al final acababa con un montón de conexiones “zombies” (en modo sleep y consulta a NULL) por culpa de CodeIgniter. La solución final fue sencilla: desactivar esta opción en los proyectos que me estaban dando problemas y ¡listo! Como por arte de magia mi show processlist estaba limpio y no tenía más conexiones zombies.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Configurando Karma en un proyecto JavaScript</title>
   <link href="http://juanmirod.github.io/2016/04/29/configurando-karma-en-un-projecto-javascript.html"/>
   <updated>2016-04-29T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/04/29/configurando-karma-en-un-projecto-javascript</id>
   <content type="html">&lt;p&gt;Este es el segundo de una serie de artículos sobre tests automáticos. Puedes encontrar el artículo anterior, que habla sobre Jasmine y TDD &lt;a href=&quot;http://juanmirod.github.io/2016/04/21/tests-unitarios-en-javascript.html&quot;&gt;aquí&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Como decía en el artículo anterior, una de las herramientas imprescindibles para trabajar con TDD es tener una visión que se actualice automáticamente con el resultado de los tests al guardar tus cambios. De esta forma puedes trabajar más cómodamente sin tener que estar cambiando de ventana y ejecutando los tests a mano.&lt;/p&gt;

&lt;p&gt;Lo ideal sería tener dos monitores para poder tener uno sólo con el editor y el otro para la ventana de los tests, la de la aplicación o la documentación que estemos consultando en ese momento. Si no tenemos dos monitores pues tendremos que hacer el mejor uso que podamos del que tenemos y ponerlo a pantalla partida, utilizar varios escritorios virtuales o lo que más nos guste.&lt;/p&gt;

&lt;p&gt;Una vez dicho esto, ¿Cómo hago, trabajando con javascript, para que la ventana del navegador o la consola estén comprobando si guardo cambios en el código y se actualicen? Hoy voy a mostrar como hacer esto con Karma, que me parece una de las opciones más rápidas y sencillas. Aunque hay muchas otras opciones para esto.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://karma-runner.github.io/0.13/index.html&quot;&gt;Karma&lt;/a&gt; es un entorno que monitoriza los archivos del código y cuando comprueba que ha habido cambios ejecuta nuestra suite de tests, es justo lo que necesitamos ahora mismo, ni más ni menos. Lo creo el equipo de AngularJS y es una herramienta fiable y que goza de buena salud en cuanto a mantenimiento.&lt;/p&gt;

&lt;p&gt;Para usarlo debemos tener instalado node y npm en nuestro ordenador. Si no lo tienes aún y te quieres dedicar a trabajar con JavaScript de forma seria te recomiendo que lo instales aunque no te interese Karma. Para más info sobre cómo instalar node, puedes ver &lt;a href=&quot;http://juanmirod.github.io/2017/08/09/introduccion_nodejs.html&quot;&gt;Mi artículo de introducción a Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Siguiendo con el ejemplo de la calculadora, para instalar Karma, primero creamos el paquete npm para el proyecto. Esto en realidad no es más que un fichero &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; que contiene información sobre las dependencias de nuestro proyecto y una pequeña descripción, la licencia y demás. Para crearlo, desde línea de comandos podemos hacer:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; npm init &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Una vez creado sólo tenemos que escribir:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;karma &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;karma-jasmine karma-chrome-launcher &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este comando instalará Karma en nuestro proyecto dentro de la carpeta &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;. La segunda línea instala los plugins para utilizar Jasmine como framework de tests y para poder ejecutar el navegador de forma automática. Como karma está instalado dentro de la carpeta node_modules, para ejecutarlo tendríamos que hacer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./node_modules/karma/bin/karma start&lt;/code&gt; Como eso es un poco royo, podemos instalar el comando karma-cli que busca nuestra instalación local aunque lo invoquemos sin la ruta:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;npm &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; karma-cli

&lt;span class=&quot;c&quot;&gt;# Ahora podemos ejecutar karma simplemente diciento&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; karma start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Pero si hacemos &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;karma start&lt;/code&gt; veremos que no pasa nada. Una vez instalado, tendremos que crear el fichero de configuración de Karma, que es parecido al de npm y que se puede crear con el mismo comando:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$&amp;gt;&lt;/span&gt; karma init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Se nos preguntarán ciertas cosas sobre el proyecto. Decimos que navegador queremos ejecutar, el framework de tests, que en este caso es Jasmine y luego indicamos, por orden o mediante comodines, los scripts que queremos que karma monitorize y cargue en el entorno de test. Es importante aquí que si necesitamos que los archivos se carguen en un orden concreto porque no utilizamos un gestor de módulos, los pongamos en ese orden en el fichero de configuración de karma. En nuestro projecto de ejemplo, como sólo tenemos tests para el módulo de la lógica, podemos añadir sólo ese módulo y su fichero de tests, estos serían los ficheros:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;calculator.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;calculator.spec.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Una vez añadidos los ficheros, podemos volver a ejecutar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;karma start&lt;/code&gt; y esta vez deberíamos ver el resultado de ejecutar los tests en la consola. Conforme vayamos ampliando el proyecto podemos añadir más ficheros o patrones concretos, Karma permite más opciones en cómo y dónde cargar los ficheros, pero por ahora nos valdrá con esto.&lt;/p&gt;

&lt;p&gt;A partir de aquí ya sólo tenemos que poner la consola en un lugar visible y seguir desarrollando. Cada vez que modifiquemos un fichero, Karma volverá a ejecutar los tests y veremos el resultado actualizado. De esta forma podemos refactorizar el código sin miedo porque veremos rápidamente si rompemos alguno de los tests. De la misma forma podremos trabajar utilizando TDD: Creamos un nuevo test que especifique un requerimiento o historia, vemos como falla, implementamos el código que lo satisface y comprobamos que así es y vuelta a empezar.&lt;/p&gt;

&lt;p&gt;Aprender a trabajar realizando los tests por adelantado es difícil al principio, hay que resistir la tentación de escribir el código directamente y al principio nos cuesta pensar en cómo escribir los tests, pero los beneficios de esta práctica están demostrados y merece la pena invertir un poco de esfuerzo extra en aprenderla. Una herramienta como Karma es fundamental para poder ver inmediatamente el resultado de los tests y poder usar esta metodología de trabajo.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Tests unitarios en JavaScript con Jasmine</title>
   <link href="http://juanmirod.github.io/2016/04/21/tests-unitarios-en-javascript.html"/>
   <updated>2016-04-21T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/04/21/tests-unitarios-en-javascript</id>
   <content type="html">&lt;p&gt;Los tests unitarios son una herramienta excelente para prevenir bugs en ejecución y para describir el comportamiento que debe tener el código. Además, y &lt;a href=&quot;http://research.microsoft.com/en-us/groups/ese/nagappan_tdd.pdf&quot;&gt;sobre todo si se realizan antes que el código&lt;/a&gt; de la aplicación (lo que se conoce como &lt;strong&gt;TDD&lt;/strong&gt;), los test unitarios ayudan a estructurar mejor el código, hacerlo más modular e independiente y además ayudan a dividir los problemas y hacerlos más sencillos de programar.&lt;/p&gt;

&lt;p&gt;En JavaScript, &lt;a href=&quot;https://jasmine.github.io/2.4/introduction.html&quot;&gt;Jasmine&lt;/a&gt; es un framework de test que permite crear tests fáciles de leer de forma que sirven también de documentación para el código. Así, usando Jasmine, si queremos escribir una suit de tests para una función que suma dos números llamada ‘add’ la escribiríamos así:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
  &lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;add function&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;should add two numbers&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// código del test&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;should throw an error if you try to add strings&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// código del test&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
  
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Vamos a ver algunos ejemplos de código y sus correspondientes tests. El proyecto es una sencilla calculadora en JavaScript, pero es diferente a los típicos ejemplos de calculadoras en javascript, ya que en esta no se utiliza eval para calcular los resultados, sino que el input se valida y las operaciones están limitadas a las que están definidas. Para ello he creado dos pequeños módulos, uno para la lógica y otro para el interface.&lt;/p&gt;

&lt;p&gt;El proyecto es un ejemplo sencillo, según las especificaciones de cada proyecto serán pertinentes más o menos tests y habrá que controlar casos más concretos, espero que este proyecto sirva de ejemplo aunque no sea muy exhaustivo ni tenga muchos requisitos.&lt;/p&gt;

&lt;p&gt;Empezaremos con los test de la clase que controla el funcionamiento de la calculadora por ser más sencillo. Cuando tienes una clase que no realiza operaciones de entrada salida, ni modifica el DOM o interacciones del usuario es mucho más sencillo escribir los tests. A eso me refería antes con que escribir los tests primero te ayuda a separar el código y a promueve mucho el principio de que cada función se encargue sólo de una cosa. En problemas fáciles como este de la calculadora, es fácil verse tentado a poner todo el código junto, meter un par de funciones en el código que maneja el interface y listo.&lt;/p&gt;

&lt;p&gt;El problema viene a largo plazo, cuando el cliente dice que además de calcular tiene que mostrar el resultado intermedio y luego te dicen que al meter un símbolo que no debería hacer nada la calculadora da un error muy feo, o que debería poder guardar en memoria un resultado… Y empezamos a poner más código en esas funcioncitas en medio del interface y esas funcioncitas van creciendo hasta tener cientos de líneas de código y… seguro que ya sabes por donde voy. Nuestra sencilla calculadora, que habíamos programado en un par de horas, crece hasta convertirse en una pesadilla de mantener y de modificar. Y además nuestro jefe no entiende cómo puede ser que hicieramos la calculadora en un día pero ahora para añadir una funcionalidad &lt;em&gt;obvia&lt;/em&gt; tardemos una semana.&lt;/p&gt;

&lt;p&gt;Por eso es por lo que en esta ocasión vamos a usar TDD y vamos a escribir primero unos tests de lo que queremos que nuestra calculadora haga:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;// Calculator.spec.js&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;should have a storeAction function&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeDefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  
  &lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;RESET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;should return the last result for unkown actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;HI&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;HI&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;should add numbers&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ADD&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;RESULT&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;should multiply numbers&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;MULTIPLY&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;RESULT&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt; 

&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Bien, ya sabemos lo que queremos, una calculadora que sume y multiplique, y que no admita cualquier cosa por la entrada. Para implementar esto nuestro Módulo calculadora debe tener una función &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;storeAction&lt;/code&gt; que será la que utilizaremos para introducir la siguiente operación o número sobre el que la calculadora debe operar, imitando el funcionamiento normal de una calculadora clásica. La functión &lt;strong&gt;beforeEach&lt;/strong&gt; es una función de &lt;em&gt;Jasmine&lt;/em&gt; que se ejecutará antes de cada función &lt;strong&gt;it&lt;/strong&gt; y que nos sirve para asegurarnos de que antes de cada test partimos del mismo estado inicial.&lt;/p&gt;

&lt;p&gt;Estos tests están bien para comenzar, pero si nos fijamos veremos que hay muchos más casos que controlar, como ¿qué pasa si añado dos números seguidos? ¿y si añado dos operaciones? ¿Donde está el test para la función de &lt;em&gt;RESET&lt;/em&gt;? Todos estos test deberán ir añadiendose y satisfaciéndose en el código.&lt;/p&gt;

&lt;p&gt;Si solo tenemos los tests y los ejecutamos en la línea de comandos o en el navegador, veremos que fallan. Para ejecutarlos lo más sencillo es crear un fichero &lt;em&gt;html&lt;/em&gt; en el que añadiremos los scripts de jasmine que están alojados en el CDN de jsdeliver. A continuación añadimos los ficheros js de nuestra aplicación y los ficheros que contienen los tests para los diferentes módulos:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewport&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width=device-width, initial-scale=1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Sample Unit tests runner&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://cdn.jsdelivr.net/jasmine/2.4.1/jasmine.css&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://cdn.jsdelivr.net/jasmine/2.4.1/jasmine.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://cdn.jsdelivr.net/jasmine/2.4.1/jasmine-html.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://cdn.jsdelivr.net/jasmine/2.4.1/boot.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;calculator.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;calculator.spec.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

  
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Al abrir este fichero en el navegador, Jasmine creará un pequeño interface y listará los tests junto con los resultados y los errores que hayan ocurrido. En este caso, si sólo tenemos el fichero de especificaciones, todos los tests fallarán.&lt;/p&gt;

&lt;p&gt;Para satisfacerlos, deberemos crear el módulo &lt;strong&gt;Calculator&lt;/strong&gt; y añadir la función &lt;strong&gt;storeAction&lt;/strong&gt; con la funcionalidad suficiente para que satisfaga los tests:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;// Calculator.js&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Calculator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;strict mode&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    
  &lt;span class=&quot;nx&quot;&gt;lastResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  
  &lt;span class=&quot;nx&quot;&gt;setLastResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;lastResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  
  &lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
    
    &lt;span class=&quot;na&quot;&gt;isNumeric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;isNaN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;isFinite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;na&quot;&gt;storeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNumeric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNumeric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;parseFloat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ADD&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;setLastResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            
          &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;MULTIPLY&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;setLastResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;lastResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;num&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                        
          &lt;span class=&quot;nl&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;setLastResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// new operation&lt;/span&gt;
        
        &lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isNumeric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        
          &lt;span class=&quot;nx&quot;&gt;setLastResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;RESET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        
          &lt;span class=&quot;nx&quot;&gt;setLastResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 

      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;lastResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
&lt;span class=&quot;p&quot;&gt;})();&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Este código satisface los tests de arriba y algunos más. Aún nos quedaría añadir la funcionalidad para restar, dividir, limpiar el input, etc. Puedes ver el ejemplo algo más completo en &lt;a href=&quot;https://thimbleprojects.org/juanmirod/56250/&quot;&gt;este thimble&lt;/a&gt;. Para ver el resultado de los tests haz click en el fichero ‘test.html’.&lt;/p&gt;

&lt;p&gt;Si te fijas, en ese projecto no hay tests para la parte del interface de la calculadora. Hay funciones del interface que no tiene mucho sentido testar, el markup puede cambiar sin alterar la funcionalidad y no tiene mucho sentido escribir tests para algo así. Pero sí que podemos escribir tests que verifiquen que, cuando hago click en un botón o pulso una tecla, se llama a la función adecuada. Estos tests son algo más complicados  ya que tenemos que capturar los eventos y espiar las funciones que estos deben llamar.&lt;/p&gt;

&lt;p&gt;Thimble es una buena herramienta para practicar TDD ya que el proyecto se va guardando y la vista se actualiza de forma automática. Pero necesitamos de conexión a internet y no tiene la velocidad y las ayudas de editores como Sublime o VSCode. Para conseguir que la vista se actualice automáticamente como en Thimble en nuestro proyecto en local podemos utilizar varias herramientas diferentes. En el siguiente artículo me centraré en cómo añadir &lt;a href=&quot;https://karma-runner.github.io/0.13/index.html&quot;&gt;Karma&lt;/a&gt; a nuestro proyecto y utilizarlo para trabajar con TDD.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Órdenes por voz para móviles Android</title>
   <link href="http://juanmirod.github.io/2016/03/30/Ordenes-por-voz-para-Android.html"/>
   <updated>2016-03-30T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/03/30/Ordenes-por-voz-para-Android</id>
   <content type="html">&lt;p&gt;Siempre me llama la atención como el márketing tiene muchas veces más poder para decidir que producto es el más conocido, por encima incluso de la calidad de los productos.&lt;/p&gt;

&lt;p&gt;En este caso, el márketing de Apple ha conseguido que todo el mundo hable de Siri,
pero en cualquier móvil, tablet o portátil podemos utilizar órdenes por voz gracias a Google, solo que este último obviamente no nos lo ha hecho llegar  al público tan contundentemente.&lt;/p&gt;

&lt;p&gt;Si tenemos la barra de búsqueda en la portada de nuestro móvil Android, simplemente con decir “Ok, Google” el móvil se pondrá a “escuchar” y podremos darle órdenes como guardar una nota, enviar un mensaje de texto o un email, llamar a alguien o hacer una búsqueda por internet y a su vez Google nos responderá en voz alta y en Español. Como Siri, pero sin fanáticos de la manzanita enseñándoselo a todos sus amigos como si hubieran comprado un prototipo del MIT robado de sus centros de investigación.&lt;/p&gt;

&lt;p&gt;A continuación, listo algunas de las órdenes que podemos decirle a Google y si queréis saber más sobre como configurar esta aplicación en móvil o pc podéis verlo &lt;a href=&quot;https://support.google.com/websearch/answer/2940021?hl=es&quot;&gt;aquí&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;alarmas-calendario-recordatorios&quot;&gt;Alarmas, calendario, recordatorios:&lt;/h3&gt;
&lt;p&gt;Simplemente dilo: &lt;em&gt;“Alarma para las siete de la tarde”&lt;/em&gt; o &lt;em&gt;“temporizador en 10 minutos”&lt;/em&gt; y el móvil creará una alarma para ese momento, sin tener que hacer click en el reloj, rellenar horas ni confirmar nada. Lo dices, lo tienes, bum!&lt;/p&gt;

&lt;h3 id=&quot;llamadas-mensajes-correos&quot;&gt;Llamadas, mensajes, correos:&lt;/h3&gt;
&lt;p&gt;También puedes decir &lt;em&gt;“Llamar a Paco”&lt;/em&gt; y listo, comenzará la llamada. &lt;em&gt;“Enviar un mensaje a Mamá que diga: llego tarde para la cena”&lt;/em&gt; y listo, no hay que navegar por los menús del móvil ni escribir nada. Puedes decir &lt;em&gt;“Email para Ana”&lt;/em&gt; y el móvil te preguntará en voz alta cuál es el mensaje y continuará interactuando mediante la voz para enviar el mensaje o cancelarlo.&lt;/p&gt;

&lt;h3 id=&quot;indicaciones-de-maps&quot;&gt;Indicaciones de maps:&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;“Indicaciones para Logroño”&lt;/em&gt; nos abrirá maps y nos responderá en voz alta con el tiempo del viaje, el estado de la carretera y la hora estimada de llegada.&lt;/p&gt;

&lt;h3 id=&quot;búsquedas-fórmulas-matemáticas-respuestas-rápidas&quot;&gt;Búsquedas, fórmulas matemáticas, respuestas rápidas:&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Averiguar la hora: &lt;em&gt;“¿Qué hora es en Londres?”&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Comprobar el tiempo: &lt;em&gt;“¿Necesito una chaqueta para hoy?”&lt;/em&gt; o +”¿qué tiempo va a hacer mañana por la mañana?”*&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Responder a preguntas triviales: &lt;em&gt;“¿Dónde nació Albert Einstein?”&lt;/em&gt; o &lt;em&gt;“¿qué edad tiene Beyoncé?”&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Traducir palabras o frases: &lt;em&gt;“¿Cómo se dice ‘pepino’ en inglés?”&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Definir una palabra: &lt;em&gt;“¿Qué significa ‘gula’?”&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Convertir unidades: &lt;em&gt;“¿Cuántos kilos son 16 onzas?”&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Resolver problemas matemáticos: &lt;em&gt;“¿Cuál es la raíz cuadrada de 2.209?”&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Las preguntas de respuesta única serán respondidas en voz alta, mientras que las que devuelvan una búsqueda de internet nos mostrará los mismos resultados que si hubieramos escrito la pregunta en el cajetín de búsqueda.&lt;/p&gt;

&lt;p&gt;Además el servicio de escritura por voz para cualquier texto que tengas que escribir también mejora por momentos. Cada vez es menos necesario escribir, y en el móvil, donde el espacio es reducido y muchas veces estamos en movimiento la voz es un sustituto perfecto. Hoy me he centrado en el servicio de Google y nombrado de pasada el archiconocido Siri, pero Amazon también ofrece Alexa, que además está disponible para que desarrolladores de aplicaciones puedan utilizarlo e introducir los interfaces por voz sin más que usar un servicio web. Poco a poco los servicios por voz irán tomando más y más protagonismo en los próximos años, dentro de no mucho nuestros hijos nos mirarán extrañados si utilizamos un teclado o un ratón y no comprenderán por qué nos seguimos aferrando a esas herramientas del pasado.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Demis Hassabis, el hombre que dejará obsoleto al género humano</title>
   <link href="http://juanmirod.github.io/2016/03/13/Demis-Hassabis-el-hombre-que-nos-dejara-obsoletos.html"/>
   <updated>2016-03-13T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/03/13/Demis-Hassabis-el-hombre-que-nos-dejara-obsoletos</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/public/img/demis-hassabis-640x360.jpg&quot; alt=&quot;Primer plano de Demis Hassabis mirándo a la cámara con una media sonrisa&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Demis Hassabis es un genio que me ha fascinado desde antes incluso de saber su nombre.&lt;/p&gt;

&lt;p&gt;Ya cuando Lionhead publicó Back and White, Peter Molineux hablaba en sus entrevistas de un prodigio de la programación que había sido el propiciante de Theme Park y que lo era de B&amp;amp;W. De la boca de Peter Molineoux todo suena siempre pretencioso, pero si miramos los dos juegos de los que estamos hablando y el momento en el que aparecieron, veremos que los dos son juegos de relevancia histórica por la misma razón: son hitos en la inteligencia artificial aplicada a videojuegos.&lt;/p&gt;

&lt;p&gt;B&amp;amp;W podría resultar vacío de contenido o un poco tonto en cuanto a reto para el jugador, pero ver cómo se comportaban las criaturas y aprendían de tus actos y respondían al propio feedback de los aldeanos era genial. Theme park era más sencillo, pero si tenemos en cuenta que Demis Hassabis tenía 17 años y que inventó un género de los videojuegos con su creación, vendió millones de copias y ganó el Golden Joystick Award, ya no parece ninguna tontería.&lt;/p&gt;

&lt;p&gt;Yo no conocía su nombre y tampoco tenía más información que esa. Solo daba la casualidad de que había leído las entrevistas de Molineux y que tenía curiosidad por el desarrollo de videojuegos. Pero sabía que la persona detrás de aquellas invenciones no era una persona normal.&lt;/p&gt;

&lt;p&gt;Efectivamente, DH se enseñó a leer él solo a los 2 años, a los 4 jugaba al ajedrez y a los 13 adquirió el rango de gran maestro. Es un genio histórico, como lo fueron Einstein, Mozart o Ramanujan. Solo el tiempo nos mostrará los frutos de su trabajo, porque los humanos comunes no podemos imaginar lo que una mente como la suya está tramando o lo que conseguirá hacer a lo largo de su vida.&lt;/p&gt;

&lt;p&gt;El desarrollo de videojuegos se ve que se le quedó corto. Después de algunos juegos más sobre IA, gestión y política, se pasó a la investigación en neurociencia. Estaba interesado en conocer mejor cómo funcionan los centros de la memoria y la imaginación en el cerebro humano.&lt;/p&gt;

&lt;p&gt;El razonamiento, el análisis y la estructura del lenguage, la percepción de los sentidos: todo eso está bastante bien modelado hoy en día en los ordenadores. Los algoritmos de hoy en día, son capaces de transcribir al vuelo un dictado, de clasificar imágenes y de identificar en ellas a una persona y su estado de ánimo en el momento de la fotografía. Pueden analizar un texto y señalar errores ortográficos o gramaticales, en el caso de lenguages de programación, las herramientas de sintaxis son mucho más rápidas y precisas, gestión de dependencias, cobertura de los tests, test automáticos etc. Tenemos herramientas que nos ayudan a escribir mejores programas y a saber donde están los puntos débiles. Herramientas para distribuir, actualizar y testar los programas de forma automática. Todas estas herramientas no solo hacen nuestro trabajo más fácil, sino que hacen que hoy en día sea posible que páginas como Facebook o Google tengan un alcance global y miles de millones de usuarios.&lt;/p&gt;

&lt;p&gt;Pero la forma en la que el cerebro almacena los recuerdos y es capaz de aprender de ellos, de combinarlos y de recuperarlos sigue siendo poco menos que un misterio. DH de nuevo destacó en este campo publicando algunos artículos que le dieron renombre y que fueron a la vez muy discutidos. Su hipótesis aún tiene sus detractores, pero no cabe duda de que fue una gran aportación al campo. La revista Science la incluyó en su listado de los &lt;a href=&quot;http://science.sciencemag.org/content/318/5858/1844.1.full&quot;&gt;10 hayazgos científicos más importantes de 2007&lt;/a&gt; (es la 9 en el enlace, por los títulos cuesta encontrarla).&lt;/p&gt;

&lt;p&gt;Tras obtener el doctorado y trabajar algunos años más en investigación en neurociencia, fundó DeepMind, empresa que más tarde adquirió Google y que es la que está dando un empuje renovado y muchas alegrías al campo de la IA. Los algoritmos de DeepMind han conseguido &lt;a href=&quot;https://www.nature.com/articles/nature14236&quot;&gt;aprender a jugar a los juegos de Atari&lt;/a&gt; sólo con la información de pantalla, sin ninguna asistencia humana. También son los responsables de &lt;a href=&quot;https://deepmind.google/research/breakthroughs/alphago/&quot;&gt;AlphaGo&lt;/a&gt;, una máquina inteligente capaz de jugar al Go que ha ganado nada menos que al (hasta ahora) campeón del mundo.&lt;/p&gt;

&lt;p&gt;Sin duda después de batir al gran campeón de Go y dejar claro que puede hacer que un algoritmo razone sobre un tablero mejor que cualquier ser humano, el siguiente reto de DH tal vez sea que un ordenador trate de enfrentarse al mundo real y de aprender a moverse y realizar acciones complejas en un entorno no controlado.&lt;/p&gt;

&lt;p&gt;O tal vez no, tal vez piense que un ordenador no necesita moverse en el mundo real, o no como lo hacemos nosotros. Al fin y al cabo, las labores manuales ya las hacemos los humanos, una IA puede dedicarse a diseñar, planificar, aconsejar, ordenar y tener un gran impacto en el mundo real sin necesidad de tener un cuerpo bípedo y autónomo…&lt;/p&gt;

&lt;p&gt;Como ya he dicho antes, no corresponde a un humano del montón como yo tratar de predecir lo que una mente así podrá producir de aquí a 10 años. Pero lo que si puedo asegurar es que estaré muy atento a lo que haga.&lt;/p&gt;

&lt;p&gt;Hoy AlphaGo ha aprendido a jugar a un juego de tablero de reglas sencillas pero probabilidades infinitas y ha mejorado hasta ser el mejor jugador de todos los tiempos. Tal vez un día, una IA aprenda a mejorarse a si misma y se produzca la singularidad, la explosión de inteligencia y nosotros pasemos de ser la especie dominante de La Tierra a ser simples simios, como hormigas en un jardín para cualquier niño. Simios que por azar habitan un planeta rocoso diminuto en una esquina de la via lactea.&lt;/p&gt;

&lt;p&gt;Pero el tema de la singularidad lo dejo para otro post. Los logros de DH no se quedan, ni mucho menos, en los que yo he enumerado, para saber más sobre él y los hitos importantes de su vida podéis consultar la &lt;a href=&quot;https://en.wikipedia.org/wiki/Demis_Hassabis&quot;&gt;wikipedia&lt;/a&gt;, su propia página web donde enlaza a &lt;a href=&quot;http://demishassabis.com/publications/&quot;&gt;sus publicaciones más importantes&lt;/a&gt; o las decenas de conferencias y entrevistas que ha concedido. Un buen resumen de los hitos importantes de su carrera podéis verlo en &lt;a href=&quot;http://www.theguardian.com/technology/shortcuts/2014/jan/28/demis-hassabis-15-facts-deepmind-technologies-founder-google&quot;&gt;este artículo de The Guardian&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;actualización-a-1-de-enero-de-2025&quot;&gt;&lt;em&gt;ACTUALIZACIÓN a 1 de enero de 2025:&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;Sin modificar el artículo, (cosa que hago a menudo y es parte de la filosofía de este blog, pero en este caso no es el propósito) me gustaría añadir la charla de DH en como ganador del nobel de química de 2024 por su trabajo liderando el desarrollo del sistema AlphaFold y Alphafold 2, que ha solventado el &lt;em&gt;problema del doblado de proteínas&lt;/em&gt; Como él mismo dice, cuando AlphaGo ganó a Lee Sedol. DH comenzó a trabajar en crear un equipo que aplicara los aprendizajes de AlphaGo a este problema. Es decir, en los 8 años que hace desde que yo escribí el artículo de arriba, DH y su equipo han solventado uno de los problemas pendientes de la biología desde hacía décadas. Acelerando el descubrimiento científico en cientos de años, si tenemos en cuenta la cantidad de tiempo que habría llevado descubrir experimentalmente la forma de los millones de proteínas ahora accesibles a la comunidad científica.&lt;/p&gt;

&lt;p&gt;Por supuesto el equipo de Deepmind no sólo ha hecho eso, sino que tiene un proyecto de igual importancia en física de materiales y otros tantos en otros campos científicos. Creo que lo más adecuado era acabar este post con la charla de DH donde él mismo explica su trayectoria y hace un guiño a lo que está por venir:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/yxAJohm0l_g?si=NQqbuDil_b7ua923&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;h2 id=&quot;actualización-feb-2026&quot;&gt;Actualización feb 2026&lt;/h2&gt;

&lt;p&gt;En este documental sobre Hassabis y Deepmind se cuenta esta historia mucho mejor y con imágenes y pequeños testimonios de su infancia, incluído Peter Molineux. Me gusta que, aunque muy centrado en Demis Hassabis, también mencionan y entrevistan a otros compañeros de DeepMind como Shane Legg, David Silver y por supuesto John Jumper, el otro galardonado del premio Nobel de química.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/d95J8yzvjbQ?si=eGIGDkU-uzt1BAxC&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
</content>
 </entry>
 
 <entry>
   <title>Directivas con varias plantillas en AngularJS</title>
   <link href="http://juanmirod.github.io/2016/03/07/Directivas-con-varias-plantillas-en-AngularJS.html"/>
   <updated>2016-03-07T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/03/07/Directivas-con-varias-plantillas-en-AngularJS</id>
   <content type="html">&lt;p&gt;En varias ocasiones me he encontrado con el problema de tener que utilizar varias plantillas o “vistas” en una misma directiva en Angular. Algo que a primera vista podría resultar bastante común y que debería estar resuelto en el framework, no lo está (no sé si han introducido algo al respecto en Angular2.0). Cada cual debe usar su imaginación y el “método Angular” para encontrar la solución que mejor se adapte a sus necesidades.&lt;/p&gt;

&lt;p&gt;Yo finalmente me decanté por esta:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;factory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;templates&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;compact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;compact&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;detailed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;detailed&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;directive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;templates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restrict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;templateUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$elem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;templates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;       
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;=ngModel&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://codepen.io/anon/pen/wawOyz?editors=101&quot;&gt;Plunker con el ejemplo funcionando&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En este ejemplo se utiliza una factoría para especificar las plantillas disponibles y luego en la directiva, mediante una expresión funcional en la plantilla y tomando de los atributos el “modo” podemos seleccionar la plantilla para la directiva sin necesidad de duplicarla y sin ensuciar el nombre de la directiva con detalles sobre la plantilla.&lt;/p&gt;

&lt;p&gt;Para más detalles sobre por qué elegí esta solución y de donde sale podéis ver &lt;a href=&quot;http://stackoverflow.com/questions/19015239/angular-directive-with-multiple-templates/29758828#29758828&quot;&gt;esta respuesta en stackoverflow&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Palabras más comunes del español</title>
   <link href="http://juanmirod.github.io/2016/02/29/palabras-mas-comunes-del-espanol.html"/>
   <updated>2016-02-29T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/02/29/palabras-mas-comunes-del-espanol</id>
   <content type="html">&lt;p&gt;Hoy quería añadir un fichero con palabras en español a Klavaro para ejercitar un poco con palabras españolas. No he encontrado a primera vista ningún texto que se adecuara a lo que quería. Normalmente estaban pareadas con su traducción a otro idioma o metidas en una tabla. Yo sólo quería un montón de palabras frecuentes seguidas, de forma que luego Klavaro las toma al azar para los ejercicios de velocidad.&lt;/p&gt;

&lt;p&gt;Así que he tomado las dos primeras listas que aparecen &lt;a href=&quot;https://es.wiktionary.org/wiki/Ap%C3%A9ndice:Palabras_m%C3%A1s_frecuentes_del_espa%C3%B1ol&quot;&gt;en la lista de palabras más comunes del español de la wikipedia&lt;/a&gt; y en un momento las he reformateado con sublime en un montón de palabras separadas por espacios, que es lo que yo buscaba. Dejo aquí la lista para mi yo futuro o por si a alguien más le puede servir de utilidad:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;de que no a la el es y en lo un por me qué una te los se con para mi está si pero las su yo tu del al como le eso sí esta ya más muy hay bien estoy todo nos tengo ha este cuando sólo vamos cómo estás o soy puedo esto quiero aquí tiene tú ahora algo fue son ser he era eres así sé tienes ese bueno creo todos sus puede voy tan esa porque dónde hacer quién nunca nada él estaba están quieres va sabes vez hace ella dos tenemos puedes sin hasta sr oh entonces dios sobre usted ni has mis mejor mucho gracias ver hola solo estar les estamos siento alguien otra siempre hombre uno donde quiere parece antes ir mira vas tal tus decir han ahí poco estas nadie desde sea también tiempo gran dijo favor podemos casa gente cosas otro día buen podría debe necesito había después será hecho señor nuestro vida tener sabe quien tenía hablar buena ellos dije toda tipo fuera estado crees ven sido todas tienen menos dice haber tres cada padre años hijo nosotros claro aún seguro nuestra gusta espera ve trabajo lugar verdad pasa debo alguna quería unos esos luego mas oye quizá van mí hemos ti estos mismo algún pueden noche mundo visto cosa nombre realmente entre buenas ah somos veo hizo esas parte pues saber haciendo debes muchas casi amigo hora quizás dinero hacia haces demasiado ud pensé madre deja hoy veces debería contra primera mientras cualquier nuevo todavía debemos ustedes mal hombres tanto salir digo mujer nueva momento sería papá ves da hey importa cuánto días cuál espero mañana dame vaya iba mamá vi déjame sabía ningún buenos dr durante mierda forma allí hice único sigue bajo poder acuerdo volver nuestros haya supongo toma siquiera quieren chica dejar aunque unas idea ay dicho necesitamos viene allá ninguna significa hubiera algunos tomar sra dentro primer llama gustaría e dijiste diablos fin pasó maldita deberías muchos cree habla fui necesita policía última vete lado maldito otros razón primero cuenta amor justo chico llegar cuándo dime ok cinco dar algunas vale haré problema tuve dicen pasar mío familia viejo hago escucha pueda esté año pasado cuidado podía hacerlo eran personas tarde saben caso adónde venga fueron cuanto cerca pequeño estuvo necesitas hiciste manos estabas encontrar queda chicos estará historia número suerte cual feliz pronto amigos eh par igual venir cuatro clase trata iré capitán cierto hablando srta hagas hermano dices éste manera hacen puerta os bastante ciudad matar esposa nuestras única aqui camino cabeza tenido podrías dio tenga conozco niños mucha di creer niño cariño vino jefe miedo medio equipo habrá entrar deben muerte acerca último punto vivir haga misma realidad lleva guerra persona pienso sangre conmigo dile rápido seguir pensar seis además listo adiós entiendo ojos minutos mayor semana agua sabemos mano hija habría haz ayuda tío doctor auto diré asi ésta jamás incluso difícil noches contigo estaban paso tuvo estaré horas juego problemas piensa cuerpo quisiera queremos llamo demonios señora agente grande comida buscar digas muerto mil cara falta estuve acaba otras probablemente detrás vuelve tampoco pequeña sino siendo comer deberíamos recuerdo mala seas trabajar segundo final vemos mujeres jugar quédate poner amo importante dado odio creí suena buscando suficiente usar supuesto serio miren luz murió loco corazón piensas llamar acabo viste tierra diez resto vuelta tras hará alto culpa lamento preocupes arriba conoces fiesta morir joven ése esperar cuarto eras mire fácil tratando vine llamado perder sal chicas basta pregunta llegó haría supone ten trato recuerda padres podríamos oído rey grandes pensando hacemos hijos esperando tenías exactamente das armas pudo perro propia temo adelante lista próxima llevar abre fuerte lejos puta peor general anda darle frente meses fuiste gusto uds hermana haremos recuerdas millones diga dejó pobre ido vio estaría arma hubo llevo palabra tendrá escuela seguridad sistema tendrás disculpe asunto diciendo nave aun plan estan traje sentid o control siente sientes vive cambiar vivo trae pude decirte presidente grupo genial simplemente encontré malo sean venido tengas dale prueba propio tendré mató sola pasando doy juntos sentir perdido oportunidad gustan conseguir pueblo daré verte dijeron sale veras conoce puesto deje orden cambio perdón tendremos atrás través mitad fuerza dan ante carajo hablo espere libro ropa veré querido abajo campo decirle segura busca según derecho calle salió hablas cuántos cállate encanta ayudar junto asesino centro creía pagar vienen quise viaje estés porqué oficial posible oí acá baja estábamos mejores oficina hicieron tipos pase hacía pensaba creen modo entra dormir media pudiera seré salvar profesor excepto fuego ojalá largo línea verdadero siete ganar james sitio comprar ejército encuentra país extraño niña llega dólares placer decirme san dolor sala caballeros segunda ésa usa sueño iremos completamente totalmente coche afuera encima diría vuelto llamada estarás querida volveré señorita llegado querías bebé hazlo regresar bienvenido empezar terminar teléfono estaremos compañía necesitan pena puso serán sacar ataque apenas caja tome sucede pone serás cielo podrían dejes hagan información programa duro acabó trabajando palabras negocio ambos trabaja noticias foto veamos decía cierra lindo oír quedan paz vayan quiera hospital acaso deseo pregunto servicio aire tranquilo semanas avión estados mente alrededor voz libre muchachos irme apuesto sigues especial dieron café mensaje anoche juro dejé debajo encontramos tenia santo maestro minuto fotos hayas estuviste habitación pareces alegro dejado darme respuesta hicimos música intento parecía dejaré sexo marido vengan darte ocurre listos habían esperen señal futuro permiso situación edad atención aquel debí cama vuelva amiga demás damas debía hacerte puedas club vámonos tendría esperaba llaman ninguno alegra nivel blanco negro tonto mantener estén causa vieja viendo linda déjeme tuviste raro boca ahi finalmente película salga preguntas llamó base tuvimos luna habías ocho mayoría vienes pido tenían llevó verás volvió solía daño tengan pon perdí llamaré empieza conocer estuviera ley quieras acabar podrá dra. dejo pelo gobierno pie corre últimos abrir siguiente misión llevas regreso existe quienes miles tanta encontrado secreto bonito montón hacerle barco entiendes maldición teniente carne irá real don regalo fuimos rango palabra frequencia (ppm)disculpa traer salvo quedar hubiese detective toca lleno llegue vayas harás cualquiera podamos hablamos zona próximo increíble dejen vuelo verlo parecen pedir idiota santa mes pelea haberlo encuentro hotel uh tomó trasero tuviera prefiero dando ayer perfecto coronel honor viejos capaz teníamos podrás contacto confiar tren hacerme mirar llamas ibas cuántas estación correcto vea llevaré podido mr tratar ponte esposo muchacho sigo relación leer cerebro sargento comandante sabías pidió Jesús escuchar estarán médico dulce carta perdió ellas dejaste vista piso siéntate dejas cámara luces novia rayos quiénes estúpido regresa excelente escuche culo código error sol intenta conocí veremos debió hermosa tocar pruebas departamento funciona tienda pensado muertos banco depende podremos jugando déjalo des haberte ocurrió cita mesa unidad oigan matado intentando necesitaba seguramente especie embargo pedazo tomando abogado hablado contar mirando cena imposible hubieras reunión tía hagamos debido lee come doble cargo príncipe personal especialmente espíritu cielos deberían papel decisión aquella alma gato estrella escribir edificio obra encontró corte accidente delante dé podré cuestión guardia carrera mata soldados diablo baño posición oiga probar llame ponga espada dia humano calma pedí ganas duele puse malditos libertad aprender varios vengo negocios dirección pelear escuché vendrá prometo volverá director sube cumpleaños sur sucedió pies perra cayó nuevos llave simple vayamos saca norte espacio también papa vuelvo diferente dígame robot quedó empezó humanos quiso segundos solamente color bar novio isla date planeta quedarme parecer dará parar energía supe despues terrible río sirve llena conocido trajo escúchame digamos tomé reina oro consejo tendrán siguen mar abran órdenes interesa sentí saldrá destino volar basura baile respeto enseguida sepa pesar pasará golpe hayan hermanos normal encontraron paciente iglesia je fuerzas tomado bomba llevan derecha ojo libros evitar larga alta siga proteger sigan navidad informe subir izquierda fe éramos gracioso confía silencio cuento salgan encuentras abuelo diste princesa leo hermoso amable bolsa tuyo ex tomo vidas vestido entendido hablé enemigo arreglar tantos bajar verá quedarse crimen entender área salido adentro nena máquina intentar caballo hable peligro mía caballero partir millón duda batalla pudiste nota varias usando rojo mataste tomaré lleve verdadera soldado bonita acuerdas irse irnos cuesta nueve brazo déjenme mataron formas alguno harán traído destruir absolutamente preocupa iban estilo huele definitivamente loca entrada radio perros acabas investigación bienvenida valor muestra asesinato mando vieron aquellos frío reglas llámame desea mama abuela tarjeta presento quede malas busco irte bienvenidos acceso fondo anillo quedarte tomas pasé divertido tantas detener puertas pistola llamé tiro irás comienza velocidad partido cuidar cálmate obviamente muere uso pide escena despierta recordar presión teniendo paga llevará cambia cartas tercer echar directo canción cuantos cerrar sabia sir roma querer cambiado seria correr imagino beber envió entró cenar horrible sueños llegamos animales comenzar viva piensan sección poniendo suelo bella vuelvas piel habéis pocos perdona habia habló caer pago experiencia ayúdame asuntos proyecto defensa acción principio orgulloso metros red adonde precio diles mueve hables escuchen partes lugares llevamos bailar aléjate sentado propósito seguimos pedido llegas vos puntos perdiendo vender necesario bebe molesta dejame charles operación tv lord banda oíste resulta quedo miembros rico permite diferencia salida yendo jodido debiste dioses triste quedas u sentía azul robar pones hazme cae hogar jóvenes llegué dueño pista pan maté puto saliendo memoria puente llego compañero volviendo lucha haberme habido cabo viento camión bala imagen toque sonido universidad pareció tercera llaves broma drogas tamaño policías suficientemente necesitar llamaba tomen dejaron carga escrito temprano salgamos nuevas olvida agradezco peso pongo coger pondré pequeños seremos robó pareja líder fueras ti público trató cien calor llevaba termina dígale recibir confío viniste vosotros puedan ey sera vives cuentas arte terminado gana veía hablaré luchar respecto querían fué encantaría infierno olvides tema recién héroe marca verme creemos poderes dama guarda enfermo coño miembro hablemos quítate olvídalo sujeto maravilloso ejemplo cientos animal té viviendo llamando sugiero cuida mantén repente podías lana gustaba querría tiempos perdimos opinión bola ama vuelvan vimos quizás cuantas costa serie olvidé leyes perdiste ello aceptar obtener vuestra reloj ventana torre prisión mires señores papi dejan momentos ayudarte volveremos den comenzó bosque fuese central cansado vuestro rato quedará podria viven preocupe objetivo km tuvieron refiero detente compré asiento andar tengamos robo tropas regresen quedado enorme dejamos propios siglo hubieran consigue manejar contó cantidad fuente dedo planes ponen interesante acaban desearía merece cinta socio leí hechos sorpresa seres riesgo recoger tira millas algún deme averiguar llegará peligroso encantado crear cliente romper robots prisa entiende llevaron caminar verla podrán decidido acabamos zapatos ganado demonio limpiar gordo recuperar estemos daría agentes terminó sienta pensamos llegaron termine virus esperamos actuar verano inteligente dudo premio posibilidad faltan quédese noticia mami gustó conocía taxi pasan quita lástima dejarlo trabajas ocupado acto traté clases caray esperas visita preguntarte oficiales pensó muero primeros créeme coge preguntar conseguí corriendo muerta controlar canal verde traigo felices discutir deber unidos enviar salud lisa diferentes brazos agradable caliente aguanta recibido quedamos meter escapar aviones preparado metido levanta juez huellas películas trabajaba estarías vuelves tranquila menor árbol ó herida hambre enamorado piloto encontraste tormenta principal llevarte piernas mírame relaciones harías perdone nombres blanca show tardes sepas conocen pulso primo sheriff dejarme pasamos corta traeré cerveza estáis toques juicio íbamos estuvimos brillante agarra fueran boda olvidar monstruo traigan suelta cabello quedaré oigo escuchado olvidado silla locura propiedad joder intenté cárcel amenaza vinieron vean prensa murieron voluntad medicina crea ayudarme ultima opción decirles época taza mapa hablaba cuán pocas hielo preguntaba casas llegaste dispuesto botella tratado llevado leche balas video propias levántate esperan cierta inspector hablan total lengua extraña volví modelo eeuu huevos cocina pondrá historias aseguro estudio efecto hablaremos quédense salimos números motivo dura dirá convierte víctima refieres pierna abra trajiste tomamos resolver cortar victoria truco pongas menudo datos aparte pura normalmente vivía hiciera sois mantiene enfermedad completo vacaciones usan sistemas volvamos tensión carro traes oeste flores éxito dedos darles cuáles revisar pense escribió beso quedé lago deba veinte preocupado mato esperanza amas seguros queria inglés flota firma cine recibí pusieron parado ministro salvó reino naves estúpida consigo calles raza examen alerta naturaleza matrimonio acabado pérdida famoso tuya revista compra&lt;/p&gt;
&lt;/blockquote&gt;
</content>
 </entry>
 
 <entry>
   <title>Ámbito léxico y de bloque en JavaScript</title>
   <link href="http://juanmirod.github.io/2016/02/19/ambito-en-javascript.html"/>
   <updated>2016-02-19T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/02/19/ambito-en-javascript</id>
   <content type="html">&lt;p&gt;El ámbito de las variables en JavaScript puede ser un poco confuso a veces, pero en realidad sólo hay que seguir un par de reglas para saber a qué ámbito pertenece una variable.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;En JavaScript &lt;strong&gt;las funciones tienen su propio ámbito léxico&lt;/strong&gt;, lo que quiere decir que depende de cómo son declaradas en el código y no de cuando se ejecutan.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Sólo las funciones&lt;/strong&gt; pueden crear un nuevo ámbito y como excepción, los bloques &lt;strong&gt;catch&lt;/strong&gt; también crean su propio ámbito. Con la introducción de las variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;let&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; en ES6, también tenemos a nuestra disposición ámbito de bloque, ver más abajo para ver qué significa esto.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;¿Cómo funciona este ámbito léxico de las funciones?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;A la hora de decidir a qué ámbito pertenece una variable, el compilador de JavaScript comprueba si la variable está declarada dentro de la función donde se invoca (ámbito local de la función) si no es así, busca en el ámbito de la función que la contenga y así hasta llegar al ámbito global. &lt;strong&gt;Si la variable no fue declarada en ningún momento, el compilador la declara como variable global&lt;/strong&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;En ‘Strict mode’ el compilador no creará la nueva variable en ámbito global sino que devolverá un error por variable no declarada.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La mejor forma de ver cómo funcionan estas reglas es probándolas en directo:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;//&apos;use strict&apos;; // descomentar para ver el error al usar la variable bye&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Global: I am global. &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ObjectWithPrivateVariables&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ObjectDefinition&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Esta variable está definida dentro del ámbito de la functión ObjectDefinition&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Object: Hello. &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//var bye; // descomentar para arreglar la fuga de la variable bye al ámbito global&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;sayHi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;returnsAGreeting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// El ámbito de esta función está dentro del ámbito de OnjectDefinition&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    
    &lt;span class=&quot;na&quot;&gt;sayBye&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;byes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;bye&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Good bye!&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bye&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ObjectWithPrivateVariables&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sayHi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hi&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Accede a la variable Global&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sayBye&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bye&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Esta variable se ha declarado como global y podemos acceder a ella, cuidado!!&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sayHi&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// sayHi es undefined&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://jsfiddle.net/juanmirod/zgsgqz2j/&quot;&gt;Editar en jsfiddle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Es interesante jugar un poco con el script, mover las declaraciones de sitio y ver que pasa.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Ok, lo he pillado y ahora ¿Qué es eso del ámbito de bloque?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En ES6 se introdujeron los tipos de variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;let&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; que no funcionan como las variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var&lt;/code&gt; sino que tienen ámbito de bloque (block scope). Esto significa que estas variables existen dentro del bloque donde son declaradas, independientemente de si ese bloque es una función, una condición o un bucle. Además, las variables declaradas con let y const no se pueden utilizar antes de ser declaradas.&lt;/p&gt;

&lt;p&gt;Esto es muy útil para declarar variables dentro de bucles o condiciones y que estas variables no se &lt;em&gt;“filtren”&lt;/em&gt; al ámbito de la función. Siempre es más fácil explicarlo con un poco de código:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;countTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;// console.log(i) // descomentar dará un error, i no está definida&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// undefined&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// console.log(i) // descomentar dará un error, i no está definida&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 10&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;countTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://jsfiddle.net/juanmirod/r2wLyvg3/&quot;&gt;Editar en jsfiddle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Algo muy curioso de este pequeño código es el diferente resultado de los dos primeros &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt; Las variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;let&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; no permiten ser usadas antes de ser declaradas, pero las variables declaradas con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var&lt;/code&gt; sí. Esto es debido a una propiedad que se llama &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hoisting&lt;/code&gt;, que quiere decir que el compilador de JavaScript hace una primera pasada por todo el código para ver qué variables y funciones hemos definido y asignarles su ámbito. Hasta que la ejecución no llegue al punto de la asignación la variable tendrá el valor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undefined&lt;/code&gt;. Esto no ocurre con &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;let&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt;, que no son creadas hasta que la ejecución no llega al punto donde son declaradas. Así, si creamos una variable de bloque dentro de una condición que no se cumple, nunca se creará, y estaremos ahorrando ese tiempo y esa memoria.&lt;/p&gt;

&lt;p&gt;Estas propiedades hacen que las variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;let&lt;/code&gt; y &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; sean consideradas más fáciles de entender, que es lo importante, y actualmente las guías de estilo de código recomienden su uso sobre var. Si usas un linter, lo más seguro es que, si usas var, te lo marque como un warning o un error.&lt;/p&gt;

&lt;p&gt;La diferencia entre let y const es que las variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const&lt;/code&gt; no se pueden reasignar, con lo que en el caso de valores escalares (cadenas, números y booleanos) son efectivamente constantes.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// ningún problema&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// y = 8 // Error, &apos;y&apos; no puede volver a asignarse por ser una constante&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// pt = &apos;otracosa&apos; // Error, pt no puede volver a asignarse&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// sin problema, ahora pt.x vale 15 en lugar de 0&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;En el ejemplo de código puede verse que no ocurre así con los objetos, porque lo que no se puede modificar es la referencia que contiene esa variable, pero sí podremos modificar las propiedades internas del objeto, (a no ser que estén congeladas, pero de eso hablaremos otro día).&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Listenings estimulantes</title>
   <link href="http://juanmirod.github.io/2016/02/02/listenings-estimulantes.html"/>
   <updated>2016-02-02T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2016/02/02/listenings-estimulantes</id>
   <content type="html">&lt;p&gt;La mejor forma de asimilar y reforzar un idioma es escuchándolo y leyéndolo. Siempre que alguien que quiere mejorar en inglés me pregunta digo lo mismo: leer y escuchar todo lo que puedas, cualquier exposición al idioma es buena, hace a nuestro cerebro familiarizarse con los sonidos y palabras, con las construcciones sintácticas y con el ritmo del discurso, aunque no se entienda todo o se tengan que leer los subtítulos (pero úsalos sólo si realmente los necesitas; si no, es mucho mejor sin ellos, podemos centrarnos en escuchar y no en leer).&lt;/p&gt;

&lt;p&gt;Pero los listenings son aburridos. Todos acabamos hartos, tarde o temprano, de escuchar conversaciones sobre hoteles, tiendas de fruta, supermercados o diálogos de máquina de café. Y las películas muchas veces tienen poco diálogo y la mayoría son americanas y el vocabulario suele ser también siempre parecido.&lt;/p&gt;

&lt;p&gt;Por suerte hoy en día tenemos internet, que es una fuente infinita de videos y que además de gatos y bebés, tiene miles de vídeos interesantes, edificantes y educativos para mejorar el idioma mientras nos entretenemos.&lt;/p&gt;

&lt;p&gt;A continuación dejo una lista con los videos y audios que me han gustado más y considero más interesantes para escuchar inglés británico (ese encantador &lt;a href=&quot;https://www.youtube.com/watch?v=wEcbQrps0dQ&quot;&gt;British accent&lt;/a&gt; ;)) Iré añadiendo vídeos a la lista conforme vaya encontrando más y si sabes de algunos que podrían añadirse puedes escribirme en &lt;a href=&quot;https://github.com/juanmirod/juanmirod.github.io/blob/master/_posts/2016-02-02-listenings-estimulantes.markdown&quot;&gt;github&lt;/a&gt; o en &lt;a href=&quot;https://twitter.com/juanmirod&quot;&gt;twitter&lt;/a&gt;. ¡Gracias!&lt;/p&gt;

&lt;h2 id=&quot;videos-de-ciencia-con-acento-británico&quot;&gt;Videos de ciencia con acento británico:&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Los videos de &lt;a href=&quot;https://www.youtube.com/user/sixtysymbols&quot;&gt;Sixty Symbols&lt;/a&gt; y &lt;a href=&quot;https://www.youtube.com/user/nottinghamscience&quot;&gt;Nottinghan Science&lt;/a&gt; son entrevistas a profesores de la universidad de Nottinghan sobre curiosidades ciéntíficas y explicaciones de fenómenos físicos y astronómicos principalmente. Los profesores tienen diferentes procedencias y acentos y es un buen entrenamiento para el oído a la par que interesante para todo científico o curioso en general. Otros canales como &lt;a href=&quot;https://www.youtube.com/user/numberphile&quot;&gt;Numberphile&lt;/a&gt; o &lt;a href=&quot;https://www.youtube.com/user/Computerphile&quot;&gt;Computerphile&lt;/a&gt; siguen la misma línea pero en otros temas, en este caso matemáticas y informática respectivamente.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Más curiosidades científicas, con un perfecto inglés de la BBC es &lt;a href=&quot;https://www.youtube.com/channel/UCdsOTr6SmDrxuWE7sJFrkhQ&quot;&gt;Brit Lab&lt;/a&gt;. Muy entretenido y muy British.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Otro canal de curiosidades, éste más general (científicas, históricas, sociológicas…) es el canal de &lt;a href=&quot;https://www.youtube.com/channel/UCBa659QWEk1AI4Tg--mrJ2A&quot;&gt;Tom Scott&lt;/a&gt;, también interesante, británico y un poco excéntrico.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lecturas-y-charlas-que-te-dejarán-marca&quot;&gt;Lecturas y charlas que te dejarán marca:&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://youtu.be/90b1MBwnEHM&quot;&gt;Shaking hands with death, by Terry Pratchett&lt;/a&gt;. Esta lectura es, como todas los textos de Terry Pratchett, inteligente, divertida, satírica y llena de reflexión. Podrás escuchar un poco al propio Pratchett aunque la lectura está espectacularmente ejecutada por Tony Robinson.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://soundcloud.com/nypl/neil-gaiman-reads-a-christmas-carol&quot;&gt;A Christmas Carol read by Neil Gaiman&lt;/a&gt;. Neil Gaiman leyó en honor a Dickens su cuento de Navidad, obra que el propio Dickens interpretó decenas de veces haciendo un tour por Estados Unidos.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://longnow.org/seminars/02015/jun/09/how-stories-last/&quot;&gt;How stories last&lt;/a&gt;. Lectura de Gaiman sobre las historias y como perduran y se transforman con el tiempo. Sin desperdicio.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://soundcloud.com/neilgaiman/the-man-who-forgot-ray-bradbury&quot;&gt;The man who forgot Ray Bradbury&lt;/a&gt;. Lectura de Neil Gaiman de un relato corto del propio Gaiman.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.ted.com/talks/jk_rowling_the_fringe_benefits_of_failure&quot;&gt;The Fringe benefits of failure by J.K. Rowling&lt;/a&gt;. Discurso de la escritora en un acto de graduación de la Universidad de Harvard. Si no has leído Harry Potter, siempre lo recomiendo en versión original como lectura sencilla y muy entretenida para todos los públicos.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.ted.com/talks/ken_robinson_says_schools_kill_creativity&quot;&gt;Do schools kill creativity?&lt;/a&gt; Una de las charlas más conocidas de TED, Sir Ken Robinson se pregunta si la escuela está limitando más que educando a los niños.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://www.abc.net.au/radio/programs/shortandcurly/&quot;&gt;How to escape education’s death valley&lt;/a&gt; Otra charla de Sir Ken Robinson sobre la educación estandarizada y la falta de inclusión.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.ted.com/talks/johann_hari_everything_you_think_you_know_about_addiction_is_wrong&quot;&gt;Everything you think to know about addictions is wrong&lt;/a&gt; Otra charla de TED, esta vez sobre el verdadero causante de las addicciones.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.ted.com/talks/ann_morgan_my_year_reading_a_book_from_every_country_in_the_world&quot;&gt;A book from every country&lt;/a&gt; Charla de TED sobre la diversidad del planeta y las pequeñas burbujas en las que vivimos. En ese sentido creo que traducir libros de otras culturas es genial pero aprender idiomas para leerlos en su lengua original es aun mejor.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://youtu.be/08Cl7ii6viY&quot;&gt;General learning Algorithms&lt;/a&gt; - Demis Hassabis en la Royal Society da una charla sobre cómo están tratando de crear una inteligencia artifical general, es decir, una inteligencia artificial capaz de aprender, planificar y actuar tal y como lo hacemos los mamíferos.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si te gustaron estos listenings vuelve en algún tiempo para escuchar más y si conoces otras lecturas o charlas en inglés británico que sean interesantes puedes puedes escribirme en &lt;a href=&quot;https://github.com/juanmirod/juanmirod.github.io/blob/master/_posts/2016-02-02-listenings-estimulantes.markdown&quot;&gt;github&lt;/a&gt; o en &lt;a href=&quot;https://twitter.com/juanmirod&quot;&gt;twitter&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Por qué el voto electrónico es una mala idea</title>
   <link href="http://juanmirod.github.io/2015/10/25/por-qu-el-voto-electr-nico-es-una-mala-idea.html"/>
   <updated>2015-10-25T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2015/10/25/por-qu-el-voto-electr-nico-es-una-mala-idea</id>
   <content type="html">&lt;p&gt;En &lt;a href=&quot;https://www.youtube.com/watch?v=w3_0x6oaDmI&quot;&gt;este video de Computerphile&lt;/a&gt;, Tom Scott explica las razones por las que &lt;strong&gt;el voto electrónico es una muy mala idea y nunca deberíamos confiar en él&lt;/strong&gt;. Totalmente de acuerdo en lo que dice. Al menos con los medios actuales, sale demasiado barato amañar unas elecciones electrónicas, por muy bien pensadas que estén.&lt;/p&gt;

&lt;p&gt;Para los que no quieran ver el video completo, Tom Scott los ponga nerviosos o no sepan inglés, dejo abajo un listado de las razones principales.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/w3_0x6oaDmI&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Los puntos principales a defender en un proceso electoral son dos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Anonimato: el voto debe ser anónimo para garantizar que el votante no puede ser amenazado/sobornado para votar a un determinado partido.&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Confianza: no puedes confiar en una sola persona la responsabilidad de miles de votos, nadie es fiable al 100%.&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sobre estas dos premisas, los problemas del voto electrónico son:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Confiar en el software y en el hardware de las máquinas de votación.&lt;/li&gt;
  &lt;li&gt;El transporte de los votos para poder ser sumados con el resto.&lt;/li&gt;
  &lt;li&gt;La máquina que realiza la suma total.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Todos estos procesos son opacos al tratarse de ordenadores, todos pueden ser intervenidos y/o modificados sin que los usuarios lo noten y todos ponen en compromiso la confianza en que los votos son fielmente contados.&lt;/p&gt;

&lt;p&gt;Tom pone varios ejemplos sobre elecciones electrónicas reales que comenten grandes errores de base y que son por tanto muy poco fiables, ¿Conoces otros ejemplos? ¿Te gustaría contribuir a este post? Puedes hacerlo en &lt;a href=&quot;https://github.com/juanmirod/juanmirod.github.io/blob/master/_posts/2015-10-25-por-qu-el-voto-electr-nico-es-una-mala-idea.markdown&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Descargar un canal de youtube desde línea de comandos</title>
   <link href="http://juanmirod.github.io/2015/10/23/descargar-un-canal-de-youtube-desde-l-nea-de-comandos.html"/>
   <updated>2015-10-23T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2015/10/23/descargar-un-canal-de-youtube-desde-l-nea-de-comandos</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://rg3.github.io/youtube-dl/&quot;&gt;Youtube-dl&lt;/a&gt; es un programa de línea de comandos que sirve para descargar videos, listas de reproducción e incluso canales completos de youtube. &lt;strong&gt;De esta forma puedes verlos cuando quieras, offline, sin anuncios y sin cortes por pérdidas de conexión.&lt;/strong&gt; Algo que es especialmente útil cuando tus hijas pequeñas ven decenas de veces a la semana las mismas canciones y cuentos. O cuando quieres ver tus vídeos favoritos de youtube en un televisor “tonto” de los de antes.&lt;/p&gt;

&lt;p&gt;Los comandos que personalmente he encontrado más útiles de las cientos de opciones que permite youtube-dl:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;youtube --list-formats url-del-video
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lista los formatos disponibles para descargar de ese vídeo en concreto. Luego con la opción -f podemos indicar el identificador numérico del formato que deseamos descargar. Por defecto siempre será el mejor disponible, pero a lo mejor solo nos interesa el audio o queremos que el vídeo pese algo menos. Así, por ejemplo:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;youtube-dl -f 43 url-del-video
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Descargará el vídeo en el formato 43.&lt;/p&gt;

&lt;p&gt;Para descargar listas de reproducción vasta con copiar la url de la lista de reproducción y youtube-dl comprobará automáticamente que es una lista y tratará de descargar todos los vídeos. Podemos filtrar los vídeos por tamaño, por el orden de la lista o por número de visitas. También es muy útil la opción –download-archive que guarda en un fichero los vídeos descargados y si vuelves a ejecutar el mismo comando se descargará solamente los vídeos del canal que no se haya descargado. Muy útil para obtener los vídeos nuevos o para descargar un canal en varios pasos.&lt;/p&gt;

&lt;p&gt;Así, para descargar una lista el comando podría ser:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;youtube-dl -f 43 --download-archive .downloaded --max-filesize 30m url-de-la-lista
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Y se descargará de la lista aquellos vídeos que no estén ya descargados y tengan un peso menor a 30mb en el formato número 43.&lt;/p&gt;

&lt;p&gt;Para descargar un canal completo sólo hay que ir a la lista de los vídeos subidos del canal.&lt;/p&gt;

&lt;p&gt;###Nota para aficionados a los gestores de paquetes: 
Si descargas youtube-dl con apt-get, yum o otro gestor de paquetes, seguramente obtengas una versión bastante antigua y obsoleta que da un error al tratar de descargar listas de reproducción. &lt;strong&gt;Es mejor instalar la última versión directamente desde la web siguiendo sus instrucciones:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo wget https://yt-dl.org/downloads/2015.10.23/youtube-dl -O /usr/local/bin/youtube-dl
sudo chmod a+rx /usr/local/bin/youtube-dl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;y luego, actualizar cuando se desee haciendo simplemente &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;youtube-dl -u&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;¿Tienes alguna duda, comentario o corrección? Este post está en &lt;a href=&quot;https://github.com/juanmirod/juanmirod.github.io/blob/master/_posts/2015-10-23-descargar-un-canal-de-youtube-desde-l-nea-de-comandos.markdown&quot;&gt;github&lt;/a&gt; y puedes contribuir a hacerlo más grande y mejor.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Sobre coches autónomos y la siguiente gran crisis de empleo</title>
   <link href="http://juanmirod.github.io/2015/10/16/sobre-coches-aut-nomos-y-la-siguiente-gran-crisis-de-empleo.html"/>
   <updated>2015-10-16T00:00:00+00:00</updated>
   <id>http://juanmirod.github.io/2015/10/16/sobre-coches-aut-nomos-y-la-siguiente-gran-crisis-de-empleo</id>
   <content type="html">&lt;figure class=&quot;audio-version&quot;&gt;
  &lt;figcaption&gt;Listen to this post:&lt;/figcaption&gt;
  &lt;audio controls=&quot;&quot; src=&quot;/public/media/sobre_coches.mp3&quot;&gt;
    &lt;a href=&quot;/public/media/sobre_coches.mp3&quot;&gt; Download audio &lt;/a&gt;
  &lt;/audio&gt;
&lt;/figure&gt;

&lt;p&gt;Últimamente se habla mucho de los coches autónomos en el mundo de la tecnología. Los avances son cada vez más palpables: Google ya lleva más de un millón de kilómetros recorridos (ACTUALIZACIÓN: En Octubre de 2018 Waymo lleva 10 millones de millas recorridas y 2700 millones de millas simuladas…), &lt;a href=&quot;http://iphone.appleinsider.com/articles/15/10/19/electric-motorcycle-startup-shutters-after-losing-top-talent-to-apple&quot;&gt;Apple&lt;/a&gt; ha anunciado sus planes para poner un coche autónomo en las calles, &lt;a href=&quot;http://www.theguardian.com/technology/2015/feb/03/are-driverless-cars-the-future-of-uber&quot;&gt;Uber&lt;/a&gt; también ha invertido en esta tecnología y por su puesto, no podemos olvidarnos de Tesla, que por ahora es el que más está arriesgando, poniendo todo el hardware necesario en todos sus modelos y comenzando a ofrecer un piloto automático real (según ellos, claro, los coches de Tesla no incluyen una tecnología fundamental para el resto de empresas como es el lidar, pero el tiempo dirá si tienen o no razón). En las empresas de automoción están también investigando y poniéndose las pilas, aunque desde un punto de vista más inmediato y conservador, con sistemas de asistencia en carretera, coches que aparcan solos, te avisan o directamente giran si ven que te vas a salir de la carretera, frenan si detentan un obstáculo, etc.&lt;/p&gt;

&lt;p&gt;Para aquellos que no sepan todavía de lo que hablo o que crean que estoy hablando de algo lejano en el tiempo, por favor ved este video de Tesla:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/O-xbDK3-5ew?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;La gente habla de este tema desde un enfoque muy inmediato. Que si solventarán los problemas de tráfico o no, que si las personas se sentirán mas o menos seguras utilizándolos o si los gobiernos los permitirán antes o después. Pero para mi, el principal cambio que supondrán los coches autónomos, será la desaparición de un sector de trabajadores y el cambio total de reglas en el mercado de la automoción.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Todos los trabajadores del transporte del mundo occidental pueden considerar que su trabajo tiene fecha de caducidad.&lt;/strong&gt; En el momento en que esté permitido, las empresas no dudarán en poner camiones, furgonetas de reparto y taxis en manos de una computadora. Para ellas no es un problema ético, ni de confianza, para las empresas será una cuestión puramente aritmética: si sale mas a cuenta un ordenador que una persona a sueldo, optarán por el ordenador sin dudar.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actualmente en el sector del transporte terrestre en España trabajan más de medio millón de personas, más de dos millones y medio en Europa.&lt;/strong&gt; Por supuesto veremos la crisis golpear algo antes en EEUU como últimamente viene pasando, pero eso no impedirá a las empresas de aquí hacer lo mismo. En España ese medio millón de personas verán progresivamente como sus puestos son ocupados por máquinas que no tienen que parar para descansar ni comer, pueden conducir de noche, son más seguras y más fiables. Claro, esto también afecta a los restaurantes de carretera y áreas de descanso. Al principio los transportes necesitarán una persona a bordo por si ocurre una avería o una emergencia de algún tipo, pero luego todo el recorrido será autónomo, las tiendas y restaurantes de carretera se reorientarán para cubrir solo paradas estratégicas a turistas y viajantes.&lt;/p&gt;

&lt;p&gt;El mundo del ocio también sufrirá una nueva revolución, imaginad todas las horas que dedicamos al mes a conducir y como mucho escuchar la radio o Spotify, poder dedicarlas a leer, ver videos o jugar. Los coches modificarán su diseño para convertirse en pequeños lugares de ocio. Los retrovisores serán superfluos, la visibilidad de la carretera o la seguridad perderán importancia que ganarán el conford y las ofertas de ocio.&lt;/p&gt;

&lt;p&gt;En cuanto al mercado de la automoción, con coches que se conducen solos y pueden volver a casa cuando te dejan en el trabajo o recoger un paquete que tienes pendiente, recoger a los niños del colegio antes que a ti… tal vez no necesites tener dos coches en cada familia. Tal vez no necesitemos aparcar tanto en el centro. &lt;strong&gt;Tal vez no necesitemos comprar un coche.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compartir coche será más fácil. Habrá autobuses pequeños pero frecuentes y con líneas que se ramifican por toda la cuidad. Uber también ha visto que su futuro tiene que pasar por los coches autónomos. Imagina una flota de taxis autónomos que están repartidos y sincronizados de forma inteligente por la ciudad. En lugar de centenares de taxistas tratando de coger una carrera buena en los aeropuertos, mientras en las calles del centro no encuentras ninguno. Un taxi cuando quieres y donde quieres, sin costes extra de desplazamiento, ni bufidos porque vas sólo 3 manzanas más allá, ni costes mínimos desorbitados.&lt;/p&gt;

&lt;p&gt;Conforme los coches autónomos se conviertan en la norma, las carreteras podrán gestionarse de forma más eficiente. Con coches que tomen rutas alternativas antes de que se formen atascos, información en tiempo real del estado de las carreteras y sistemas de reparación también autónomos. &lt;strong&gt;No serán necesarios los controles de velocidad, ni los peajes, ni los controles de alcoholemia, el coche podrá ir sólo a la ITV o a la revisión al concesionario.&lt;/strong&gt; No habrá preocupaciones por si algún borracho se te cruzará en la carretera por que viajas tarde. Personas discapacitadas podrán desplazarse por carretera a cualquier distancia, bajarse y subirse siempre en la misma puerta, sin necesidad de depender de terceras personas.&lt;/p&gt;

&lt;p&gt;Mas tarde llegarán cambios en las infraestructuras. Peajes automáticos, desaparición de los semáforos no peatonales y de la señalización. No necesitaremos tantos aparcamientos en ciudades, oficinas, centros comerciales o lugares de residencia…&lt;/p&gt;

&lt;p&gt;Que los coches se conduzcan solos no es sólo una comodidad que hará que todo siga igual pero sin que tengamos que sacarnos el carné de conducir. Poco a poco cambiará la sociedad, seguro que afectando a otros muchos ámbitos que no se me han ocurrido a mi.&lt;/p&gt;

&lt;p&gt;Sobre este tema, aunque en un sentido más amplio, es muy interesante la charla de Jeremy Howard en Ted. Tras hacer un repaso de los últimos avances en inteligencia artificial, lanza una advertencia: las IAs son capaces de realizar cada vez más tareas que antes estaban consideradas exclusivamente humanas, la Revolución de la Inteligencia Artifical está llegando y será mucho más drástica que la Revolución Industrial, debemos empezar a prepararnos.&lt;/p&gt;

&lt;iframe src=&quot;https://embed-ssl.ted.com/talks/jeremy_howard_the_wonderful_and_terrifying_implications_of_computers_that_can_learn.html&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;¿Se te ocurren otras formas de aprovechar los coches autónomos en el futuro? ¿Crees que estoy totalmente equivocado? &lt;a href=&quot;https://github.com/juanmirod/juanmirod.github.io/blob/master/_posts/2015-10-16-sobre-coches-aut-nomos-y-la-siguiente-gran-crisis-de-empleo.markdown&quot;&gt;Este post está alojado en github&lt;/a&gt;, puedes contribuir con tus comentarios, correcciones y modificaciones sobre el artículo. ¡Gracias por colaborar!&lt;/p&gt;
</content>
 </entry>
 

</feed>
