<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Tomas Francisco Lingotti</title>
    <description>The latest articles on Forem by Tomas Francisco Lingotti (@tomaslingotti).</description>
    <link>https://forem.com/tomaslingotti</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F921372%2F580eee9b-5def-4d01-97f9-649b4693f53a.jpg</url>
      <title>Forem: Tomas Francisco Lingotti</title>
      <link>https://forem.com/tomaslingotti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tomaslingotti"/>
    <language>en</language>
    <item>
      <title>Entrevistas en IT</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Mon, 29 May 2023 00:03:13 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/entrevistas-en-it-1pjf</link>
      <guid>https://forem.com/tomaslingotti/entrevistas-en-it-1pjf</guid>
      <description>&lt;p&gt;Vamos a repasar los aspectos mas relevantes de un proceso de entrevistas en una compañía de IT. Desde el primer contacto hasta la resolución de ejercicios técnicos en vivo, algo que muchos desarrolladores están en contra, ya sea porque se aleja muchísimo de lo que es un trabajo o porque lo que hay que hacer en el día a día no tiene nada que ver con ese ejercicio que su respuesta esta replicada mil veces en internet. Incluso ChatGPT puede resolverlo en menos de 5 minutos.&lt;/p&gt;

&lt;p&gt;Pero por otra parte, desde el punto de vista del entrevistador, puede ver nuestra manera de pensar, de comunicarnos, como reaccionamos ante determinada situación y como trabaja nuestra cabeza cuando tiene un problema en frente y si o si hay que resolverlo. O al menos intentarlo.&lt;/p&gt;

&lt;p&gt;Comenzamos con algunos pasos:&lt;/p&gt;

&lt;h2&gt;
  
  
  Contacto
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn y referidos&lt;/strong&gt;. No creo que mandando CV al mail de la página de careers sea una buena opción.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agregar RRHH&lt;/strong&gt; de esas empresas y tener el perfil lo mas atractivo posible (hay mucha info sobre eso). Mi único consejo es investigar sobre la empresa, lenguajes y tecnologías que usa y ver si mi perfil está alineado. Tener paciencia va a ayudar mucho.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Referidos&lt;/strong&gt;: bueno, si ya tengo conocidos ahí dentro, pedir que deje nuestro CV por algún programa interno. En caso que no haya, directo a RRHH.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Etapas de la entrevista
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Suelen ser varios pasos, incluso mas de uno para validar lo mismo. El primer screening es 100% cultural y repasar el CV, muchas veces es un trámite [ver apartado de QUE NO HACER].&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En este punto podemos preguntarle a nuestro contacto como van a ser las siguientes etapas, eso nos ayuda a prepararnos mejor.&lt;/p&gt;

&lt;h2&gt;
  
  
  La temida "técnica"
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Las entrevistas técnicas son todo un reto, pueden dividirse de varias formas, las mas comunes suelen ser primero un ping pong de preguntas y 45 minutos con algún ejercicio de programación en vivo o un diseño a alto nivel de una big tech, por ej Uber/Twitter/YouTube/gateway de pago. No se espera que sea un detalle exacto ni mucho menos, pero si lo actores principales, como escalar, modelos de datos correctos, separación de intereses y demás. Hay material sobre diseño en entrevistas, pero NADA supera la experiencia.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Los ejercicios de desarrollo, son los que vemos en &lt;strong&gt;HackerRank&lt;/strong&gt;, &lt;strong&gt;Leetcode&lt;/strong&gt; y similares. Muchas veces son textual extraídos de esos sitios. Esa práctica es clave para el una resolución rápida y efectiva. Muchas veces, no buscan que el algoritmo resuelva el 100% de los casos o que este optimizado. Pero si de buscar la mejor complejidad temporal (Big O) y que cumpla al menos los test cases de ejemplo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duración: Largas, entre 1 y 2 horas seguro. Mantener agenda limpia esa mañana o tarde.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Estudiar/Prepararse
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conocer bien su CV&lt;/strong&gt;, tecnologías que manejan, proyectos trabajados, &lt;strong&gt;challenges resueltos&lt;/strong&gt;, como manejar ciertas situaciones, por ejemplo, no cumplir un deadline, un compañero “rompe” el CI el viernes a las 17.50, y cosas parecidas. Repasar experiencias y armar una buena narrativa ayuda y mucho.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algoritmos y estructuras de datos&lt;/strong&gt;. Practicar mucho, leer códigos con soluciones. Fundamental vero soluciones reales, en GitHub hay infinidad de snippets en todos los lenguajes y con muchos enfoques. Cuando nos trabamos con algo, tenemos que buscar la solución. &lt;strong&gt;No dedicar mas de 1 hora en un problema&lt;/strong&gt;. Pasado este tiempo, vamos a ver como otros lo resolvieron y re-pensar nuestros errores.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Que no hacer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Llegar tarde 🕚, siempre calcular al menos 10 min de margen. Tener mic y cámara listos.&lt;/li&gt;
&lt;li&gt;Hablar “mal” de una compañía pasada.&lt;/li&gt;
&lt;li&gt;No estar dispuesto a escuchar o recibir feedback, esto incluso podemos no darnos cuenta, pero los entrevistadores tienen herramientas para detectar estas actitudes y es un NO FIT cultural seguro. Un ejemplo es no dejar hablar al entrevistador.&lt;/li&gt;
&lt;li&gt;No saber a que se dedica la empresa a la que estamos aplicando. Una mínima investigación es necesaria.&lt;/li&gt;
&lt;li&gt;No hacer preguntas. Capaz sea un punto intermedio, pero siempre hacer preguntas sobre la posición a ocupar, metodologías, como están compuestos los equipos, nos va a dar mucho mejor panorama a la hora de decidir. No estoy realmente seguro de que influya negativamente en la entrevista, pero si nos brinda mas información a nosotros.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Salir bien en las entrevistas es un &lt;em&gt;skill&lt;/em&gt; en si mismo, antes de aplicar al trabajo de nuestros sueños, tenemos que estar preparados y saber que nunca nos vamos a sentir seguros por completo, pero eso no nos tiene que impedir tener mucha confianza en nosotros mismos y encarar los procesos. Asi que a prepararse y ser pacientes que tarde o temprano, nuestra oportunidad va a aparecer.&lt;/p&gt;

&lt;p&gt;El día de la entrevista, hay que mantenerse tranquilo y repasar mentalmente lo que vamos a decir, ya sea en nuestro idioma o en inglés.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>beginners</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>HTTP y sus formas de comunicarse</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Fri, 26 May 2023 18:13:36 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/http-y-sus-formas-de-comunicarse-2o67</link>
      <guid>https://forem.com/tomaslingotti/http-y-sus-formas-de-comunicarse-2o67</guid>
      <description>&lt;p&gt;Esta entrega va a estar dedicada a tecnologías y no implementaciones, pero aclaro que todos los métodos mencionados son capaces de ser usados con la gran mayoría de los lenguajes.&lt;/p&gt;

&lt;p&gt;La idea principal es presentar todos las formas de comunicación sobre HTTP usadas hasta ahora y compararlas en sus aristas mas importantes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qué son y para qué los necesitamos?
&lt;/h2&gt;

&lt;p&gt;Primero, tenemos que explicar brevemente que es HTTP(S). Por su siglas, es &lt;em&gt;Hyper Text Transfer Protocol&lt;/em&gt;, la S es de &lt;em&gt;Secure&lt;/em&gt; cuando los datos viajan cifrados.&lt;/p&gt;

&lt;p&gt;Las paginas de internet se basan en este protocolo para mostrar los archivos que el navegador web interprete, por ejemplo, HTML, CSS, JavaScript, imágenes, PDF y un largo etcétera. Es decir, alguien pregunta usando una URL y un puerto (80 para http y 443/8443 para https) y un server nos devuelve los archivos que el cliente sabe interpretar.&lt;/p&gt;

&lt;p&gt;Hasta acá, bastante fácil, de hecho es una arquitectura cliente-servidor estándar. Pero sabemos muy bien (y sino, lo aprendemos ahora) que los sistemas ya un poco mas grandes que una página estática, tenemos que armarnos de varias instancias, servicios web, comunicaciones asíncronas, real-time (near real time) y quien sabe cuantas cosas mas, que a veces no necesitamos, pero las usamos igual.&lt;/p&gt;

&lt;p&gt;Ejemplo que si usamos todos, un chat, no podemos hacer la arquitectura &lt;em&gt;normal&lt;/em&gt; que vimos en http, porque sería muy lento, además, no podríamos usar otras &lt;em&gt;features&lt;/em&gt; como por ejemplo,si nuestro amigo está escribiendo, no seriamos capaces de ver que lo está haciendo si usamos la arquitectura descripta anteriormente.&lt;/p&gt;

&lt;p&gt;Es por eso, que vamos a necesitar de mas y naturalmente diversas tecnologías para responder todas las demandas.&lt;/p&gt;

&lt;p&gt;Vamos a ver:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://grpc.io" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt; (desarrollado por Google)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://restfulapi.net/" rel="noopener noreferrer"&gt;REST&lt;/a&gt; (representar recursos y estados [JSON])&lt;/li&gt;
&lt;li&gt;
&lt;a href="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=&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=2ahUKEwj22vSCnpL_AhUjrZUCHTkWCcwQFnoECAkQAQ&amp;amp;url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FAPI%2FWebSockets_API&amp;amp;usg=AOvVaw2CMyKiqhXN3YmpHc4yjRv_" rel="noopener noreferrer"&gt;Webosckets&lt;/a&gt; (canal de ida y vuelta)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt; (alternativa interesante para escalar)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  gRPC 🎯 
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqv44p4wd1fxyndn0vgm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqv44p4wd1fxyndn0vgm.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Desarrollado por Google, pero open source, es un framework tipo plus and play, multiplataforma para comunicación de servicios. Es independiente al lenguaje base de programación y ofrece una serie de ventajas claras en casos de uso específicos, donde es casi siempre la mejor opción y no tiene rival. Las que mas se destacan son su eficiencia, la posibilidad de documentar con código (real) y versionar los modelos, uso de http v2, plugins de autenticación, métricas, checks de salud de las comunicaciones, load balancing y tracing.&lt;/p&gt;

&lt;h4&gt;
  
  
  que necesito y como funciona?
&lt;/h4&gt;

&lt;p&gt;Dos cosas son claves, los protocol buffers (protobuf) que son el mecanismo de serialización - lo podemos comparar con los JSON de REST- y es 100% neutral a las plataformas, sistemas operativos y lenguajes y &lt;a href="https://grpc.io/docs/protoc-installation/" rel="noopener noreferrer"&gt;el compilador protobuf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Así se define uno simple, la definición de un "objeto" Persona&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;optional&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;optional&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;optional&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No solo definir estructuras, también interfaces con métodos, o sea el comportamiento que deseamos para nuestro servicio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The greeter service definition.&lt;/span&gt;
&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;Greeter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Sends a greeting&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;SayHello&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloReply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The request message containing the user's name.&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HelloRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The response message containing the greetings&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HelloReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta definición va a ir en un archivo &lt;code&gt;.proto&lt;/code&gt;. &lt;br&gt;
Un buen lugar donde ver todo sobre protocol buffers es &lt;a href="https://protobuf.dev/programming-guides/proto3/" rel="noopener noreferrer"&gt;su sitio oficial&lt;/a&gt; y usar la version 3 (al menos a la fecha de publicación de este humilde artículo).&lt;/p&gt;

&lt;p&gt;Ahora bien, dijimos que necesitábamos el compilador protobuf y el plugin gRPC para poder generar el código que soporte nuestros archivos proto (al menos en Go).&lt;/p&gt;

&lt;p&gt;Para ejecutar el compilador, vamos a correr algo asi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;protoc &lt;span class="nt"&gt;--go_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--go_opt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;source_relative &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--go-grpc_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--go-grpc_opt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;source_relative &lt;span class="se"&gt;\&lt;/span&gt;
    proto/&lt;span class="o"&gt;{&lt;/span&gt;nuestro_archivo&lt;span class="o"&gt;}&lt;/span&gt;.proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El resultado van a ser archivos &lt;code&gt;.go&lt;/code&gt; que tienen toda la operatoria definida previamente.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ventajas 👍 
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;La principal, su rendimiento. El (des)serializado (cuando transformamos nuestro objeto Java por ej. para que viaje por la red, eso es serializar y la inversa es para leerlo cuando llega y convertimos los bytes a un objeto).&lt;/li&gt;
&lt;li&gt;Usar http2 y su tecnología superior (multiplexación de canales, tasas de transmisión mas altas, etc)&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Posibilidad de &lt;em&gt;tunear&lt;/em&gt; los servicios de acuerdo a las necesidades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sin streaming&lt;/li&gt;
&lt;li&gt;Streaming unario del servidor al cliente&lt;/li&gt;
&lt;li&gt;Streaming unario del cliente al servidor&lt;/li&gt;
&lt;li&gt;Streaming bidireccional &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Esto corresponde al ciclo de vida de una request/response en http2 y gRPC, sugiero leer &lt;a href="https://grpc.io/docs/what-is-grpc/core-concepts/#unary-rpc" rel="noopener noreferrer"&gt;esta documentación&lt;/a&gt; para entenderlo mejor.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Última ventaja, es poder ser API-first y documentar los contratos, versiones y demás con el tooling de gRPC. Ademas, poder usar versiones viejas de las APIs sin mucho esfuerzo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Desventajas 👎 
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Difícil de probar, básicamente traban en par cliente-servidor, por lo que ir a Postman o cURL no es una opción muy viable.&lt;/li&gt;
&lt;li&gt;El código generado no es legible o entendible por nosotros.&lt;/li&gt;
&lt;li&gt;Se requiere una nueva tecnología y dominarla puede llevar tiempo y errores.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  REST 🎯
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgv3hfmmzknpe7d4ad0ih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgv3hfmmzknpe7d4ad0ih.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Es largamente usado en la industria y seguramente lo siga siendo. Es la primera opción a considerar a la hora de comunicar cliente y servidor.&lt;br&gt;
En esta entrega, vamos a basar a REST con sus mensajes en JSON.&lt;/p&gt;
&lt;h4&gt;
  
  
  qué es y como funciona?
&lt;/h4&gt;

&lt;p&gt;Ahora bien, que es REST, por sus siglas, &lt;strong&gt;RE&lt;/strong&gt;presentational &lt;strong&gt;S&lt;/strong&gt;tate &lt;strong&gt;T&lt;/strong&gt;ransfer. Quiere decir que vamos a presentar recursos y manipularlos a través de estados. Vamos a crear una interfaz uniforme, que sea fácil de entender y extender conforme nuestro servicio crezca en funcionalidades.&lt;/p&gt;

&lt;p&gt;Esta interfaz se basa en reglas generales que no cambian en el servicio, esto hace que su comportamiento sea determinista tanto para los usuarios como para los desarrolladores. Algunos lineamientos aceptados son: &lt;br&gt;
(cabe destacar que estos, como todo, tienen opiniones a favor y en contra. La clave es elegir uno y no cambiarlo).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nombres de los recursos en plural para las URLs. Por ejemplo /users.&lt;/li&gt;
&lt;li&gt;Todos los recursos deben ser únicos en su nomenclatura.&lt;/li&gt;
&lt;li&gt;Usar los verbos HTTP para determinadas acciones. &lt;code&gt;POST&lt;/code&gt; para crear, &lt;code&gt;GET&lt;/code&gt; para leer, &lt;code&gt;PUT&lt;/code&gt; para actualizaciones completas y &lt;code&gt;PATCH&lt;/code&gt; para parciales. &lt;code&gt;DELETE&lt;/code&gt;, claramente, para borrar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En rest, decimos que un recurso es un conjunto de datos a los cuales le puedo aplicar algunos de los comportamientos mencionados anteriormente, usando URLs y los verbos. No es lo mismo un GET a &lt;code&gt;/users&lt;/code&gt; que un POST.&lt;/p&gt;

&lt;p&gt;Una feature que comparte REST y HTTP es que las respuestas se pueden &lt;strong&gt;cachear&lt;/strong&gt;. Interesante punto para la performance.&lt;/p&gt;

&lt;p&gt;Otros temas importantes son la idempotencia, el no-estado (conocido por stateless en inglés) y el tipo de contenido (header de content-type). Obvio que la seguridad, tokens y demás son otros puntos mas que interesantes, pero al haber tantas alternativas, es preferible dejarlo para otra entrega.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Idempotencia&lt;/strong&gt; es una característica propia de los VERBOS, no de los recursos o de las URLs. Quiere decir que una acción (URL + verbo) puede repetirse N veces sin que tenga efectos en los recursos y obtener el mismo resultado una y otra vez. Por ejemplo si ejecuto &lt;code&gt;DELETE /users/1&lt;/code&gt;, la primera vez, borro sin problemas, la segunda, no voy a borrar nada pero tampoco debería tener un error de vuelta, ya que ese ID ya fue borrado. Por eso decimos que &lt;strong&gt;DELETE&lt;/strong&gt; si es idempotente.&lt;br&gt;
&lt;u&gt;&lt;br&gt;
Esto tenemos que tenerlo claro a la hora de programar.&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;En cambio, POST, no lo es, por que si enviamos 2 veces el mismo usuario, es natural que si obtengamos un error, porque no podemos tener 2 usuarios distintos con el mismo mail. Por eso POST no lo es.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;STATELESS&lt;/strong&gt; es una de las propiedades principales de REST, quiere decir que cada petición es totalmente autocontenida y no necesita información de su antecesora. Aunque no es 100% verdad (al menos para mi) porque en APIs que requieran estar autenticado, si tenemos que hacer una antes pera validar credenciales. Pero bueno podemos discutirlo en otro momento.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JSON&lt;/strong&gt; JavaScript object notation, tal como en gRPC la comunicación era por binarios que eran el resultado de los archivos &lt;code&gt;proto&lt;/code&gt; en REST vemos que JSON es el &lt;em&gt;de facto&lt;/em&gt; para la industria. Los cuerpos de las peticiones tienen que tener un JSON válido para que pueda ser leído. Esto da mucha flexibilidad porque cualquier API puede leer mensajes de básicamente, cualquier cliente, siempre y cuando respete el contrato JSON acordado sumado a las mencionadas URL y verbo HTTP. Con este "triplete" tenemos ya toda la información necesaria para si sellar nuestro contrato y poder documentarlo. Para el estándar, esta &lt;strong&gt;OpenAPI&lt;/strong&gt; para seguir como  ejemplo.&lt;/p&gt;

&lt;p&gt;Por último en REST, otras cosas a tener en cuenta, repasar y documentar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filtros&lt;/li&gt;
&lt;li&gt;Paginación&lt;/li&gt;
&lt;li&gt;Los recursos debería tener los links asociados para operar en él&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Ventajas 👍
&lt;/h4&gt;

&lt;p&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cacheable&lt;/li&gt;
&lt;li&gt;Fácil de implementar y nativo de todos los lenguajes, ya que se basa en HTTP, entonces, no necesitamos nada mas.&lt;/li&gt;
&lt;li&gt;Ningún cliente de las APIs se va a quejar por usar REST con JSON.&lt;/li&gt;
&lt;li&gt;Para probar, tampoco necesitamos nada, un Postman, cURL, un browser, cualquiera es válido.&lt;/li&gt;
&lt;li&gt;Por lo general, front y back separados.&lt;/li&gt;
&lt;li&gt;Es un FIT muy bueno para la gran mayoría de las apps data driven.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Desventajas 👎 
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Es difícil aplicarlo de forma "pura" en todo el proyecto. Si el servicio escala conforme pasa el tiempo, muchas veces tenemos casos de uso que no cumple con las especificaciones de REST, entonces tenemos que ir adoptando excepciones y licencias para cosas nuevas y puede terminar mal.&lt;/li&gt;
&lt;li&gt;La documentación suele ser un dolor de cabeza importante.&lt;/li&gt;
&lt;li&gt;Su performance no es óptima.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Websockets 🎯
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctwk55idsau0af1injtm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fctwk55idsau0af1injtm.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Es una tecnología que permite la comunicación ida y vuelta en una sesión interactiva entre el cliente y el servidor.&lt;/p&gt;

&lt;p&gt;Se basa en una serie de &lt;strong&gt;mensajes&lt;/strong&gt; que esta API entiende, por ejemplo si enviamos solo texto (lo único que podemos enviar y que leer), un mensaje de cierre de conexión, apertura, ping para mantener la sesión abierta y alguno mas seguro debe haber, pero no los usé, ya sabiendo esos van a estar mas que bien.&lt;/p&gt;

&lt;p&gt;Para usar en cualquier lenguaje de backend, vamos a necesitar alguna &lt;strong&gt;librería&lt;/strong&gt;, ya que una implementación propia puede resultar costosa en términos de tiempo y traer algunos bugs difíciles de corregir, por eso recomiendo buscar alguna ya probada ahí afuera.&lt;/p&gt;

&lt;p&gt;Tiene muchos casos de uso, al ser tan rápido (solo enviá pocos tipos de eventos) y bidireccional, muchos chats están implementados con &lt;strong&gt;websockets&lt;/strong&gt;. Tenemos otros para enumerar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suscripción a tickets de la bolsa/criptomonedas (recibir el precio actualizado en forma de "feed").&lt;/li&gt;
&lt;li&gt;Juegos multi jugador donde necesitamos muchos datos al mismo tiempo y con baja latencia.&lt;/li&gt;
&lt;li&gt;Transmitir coordenadas en near-real-time.&lt;/li&gt;
&lt;li&gt;Herramientas colaborativas (estilo google docs)&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hay que tener en cuenta que algunos navegadores no soportan websockets, ni todas las implementaciones son iguales. Acá hay &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" rel="noopener noreferrer"&gt;una buena docu de referencia&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Ventajas 👍
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Velocidad de transmisión.&lt;/li&gt;
&lt;li&gt;Facilidad para implementarlo.&lt;/li&gt;
&lt;li&gt;Amplio soporte y herramientas.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Desventajas 👎
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;A veces no es tan trivial el debug, aunque Postman ya incluye request WS.&lt;/li&gt;
&lt;li&gt;Los "internals" son complejos, ademas de que dependemos de librerías en el 99% de los casos.&lt;/li&gt;
&lt;li&gt;No son persistentes, tampoco hay servicios cloud que provean algo así. Cierro el navegador y se cierra el websocket.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  GraphQL 🎯
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhgyeu9s3xeasl9m1fhu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhgyeu9s3xeasl9m1fhu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Que es?
&lt;/h4&gt;

&lt;p&gt;Muy complicado responder, es varias cosas! Un framework para manipulación de datos, un motor de queries hasta incluso un lenguaje (exagerando un poco). Sabemos también que es opensource y desarrollado (al principio) por &lt;a href="https://about.meta.com/" rel="noopener noreferrer"&gt;Meta&lt;/a&gt;. Para mi, lo podemos definir como una especificación para APIs.&lt;/p&gt;

&lt;p&gt;Es una alternativa a REST, no veo como una evolución natural donde lo que tenemos en REST lo podemos llevar a GQL, ni al revés, hay que pensarlo así desde el principio o en el peor de los casos, reescribir los servicios.&lt;/p&gt;

&lt;p&gt;La clave es que el cliente, con la query correcta, puede obtener los datos que necesita y nada mas, es decir, si tenemos un usuario en nuestro modelo que tiene 15 campos, podemos traer cualquier combinación de ellos, al contrario de REST, que el recurso viaja como una unidad, ya que desarrollar algo similar llevaría muchísimo trabajo.&lt;/p&gt;

&lt;p&gt;Gran ventaja es la manipulación de datos tan granular que ofrece y con un esfuerzo dentro de todo bajo si ya venciste la curva de aprendizaje.&lt;/p&gt;

&lt;p&gt;Otra ventaja es que es independiente a la fuente de datos, puede ser MySQL, mongo, etc, aunque esas conexiones queda para que nosotros las hagamos, no es plug-and-play ni mucho menos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F302fllehxbwckkg4v4ci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F302fllehxbwckkg4v4ci.png" alt="GQL engine"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Pasos a seguir
&lt;/h4&gt;

&lt;p&gt;Primero tenemos que definir un esquema (schema) donde describimos nuestro modelo. Al ser tipado, tenemos que declarar todos los tipos, nos queda de este estilo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type User {
  id: ID
  name: String
}

type Project {
  name: String
  tagline: String
  contributors: [User]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Al definir las queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Query {
  getProjects: [Project]
  getUsers: [User]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y desde el cliente deberían enviar algo así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 project {
   name
   tagline
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y el resultado esperado en JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"project"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Apollo 11"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mars-Rover"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Challenger 1"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Todo el framework viene con un tooling importante. No en todos los lenguajes es igual, algunos tienen generadores de código o corren una UI para realizar las consultas GQL de forma muy sencilla.&lt;br&gt;
El detrás de escena es el mismo, el motor funciona igual, las conexiones con las fuentes de datos también.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ventajas 👍
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Reducir drásticamente el numero de URLs, vamos a tener muchas menos (menos lineas == menos para mantener).&lt;/li&gt;
&lt;li&gt;Escalabilidad garantizada.&lt;/li&gt;
&lt;li&gt;Como los &lt;code&gt;.proto&lt;/code&gt;, la documentación es mucho mas natural y versionada.&lt;/li&gt;
&lt;li&gt;Reutilización de tipos de datos en los schemas.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Desventajas 👎
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Curva de aprendizaje&lt;/li&gt;
&lt;li&gt;No podemos hacer cache de respuestas, en REST si.&lt;/li&gt;
&lt;li&gt;Mantener el schema de GQL puede no ser trivial para desarrolladores sin experiencia con el framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bueno, hasta acá mi análisis, espero que les haya gustado, los espero en &lt;a href="https://youtube.com/tomaslingotti" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;, &lt;a href="https://twitch.tv/tomasitofl" rel="noopener noreferrer"&gt;Twitch&lt;/a&gt; y &lt;a href="https://discord.io/gophers-latam" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;PS: Comenten algún tema en particular si quieren que investigue y escriba!&lt;/p&gt;

</description>
      <category>network</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Concurrencia en Go V</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Wed, 10 May 2023 17:01:26 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/concurrencia-en-go-v-4gif</link>
      <guid>https://forem.com/tomaslingotti/concurrencia-en-go-v-4gif</guid>
      <description>&lt;p&gt;|1. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-go-i-5aao"&gt;Modelo de concurrencia&lt;/a&gt;&lt;br&gt;
|2. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-ii-484m"&gt;Goroutines y canales&lt;/a&gt;&lt;br&gt;
|3. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-iii-4g6c"&gt;Wait Groups&lt;/a&gt;&lt;br&gt;
|4. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-iv-5584"&gt;Select y Worker pools&lt;/a&gt;&lt;br&gt;
|5. | &lt;strong&gt;ErrGroup (error groups)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Primero, muchas gracias por leer la última entrega de concurrencia en Golang, en el índice encontrás todos los links para navegar entre los distintos posteos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Que son los error groups?
&lt;/h2&gt;

&lt;p&gt;Sabemos como son los errores en Go y que una parte importante es el famoso (para bien y mal en partes iguales) &lt;code&gt;if err != nil {}&lt;/code&gt; entonces, si ejecutamos, básicamente, cualquier cosa que devuelva un &lt;code&gt;error&lt;/code&gt; lo vamos a tener que manejar, aunque en un ambiente de múltiples goroutines nos surjen otras preguntas.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Que pasa si hay un error en una rutina? las siguientes deberían correr o no?&lt;/li&gt;
&lt;li&gt;Supongamos que si corren, como recolecto los errores? un &lt;code&gt;slice&lt;/code&gt; o &lt;code&gt;map&lt;/code&gt; puede generar &lt;code&gt;panic&lt;/code&gt; si se accede de forma concurrente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pueden ser más también dependiendo el contexto.&lt;/p&gt;

&lt;p&gt;La verdad es que esas 2 preguntas, no van a tener una solución nativa, solo workarounds, pero ahi es donde llega &lt;code&gt;error groups&lt;/code&gt;.&lt;br&gt;
El paquete es de de Go, pero de los que tienen X, quiere decir que no es del core, sino que es eXternal. Lo encuentrar aca:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"golang.org/x/sync/errgroup"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez importado y ya declarado en nuestro go.mod, podemos inicializarlo de dos formas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;errgroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para usar un contexto cancelable en X tiempo.&lt;/p&gt;

&lt;p&gt;O sino, directamente la estructura (o su dirección de memoria)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;eg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;errgroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Group&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora, solo tenemos que identificar el trabajo que queremos realizar de forma concurrente y luego lanzar las rutinas, pero ahora, a través de los error groups.&lt;/p&gt;

&lt;p&gt;Suponiendo que tengo unos &lt;em&gt;documentos&lt;/em&gt; que quiero enviar a un servicio externo para que sean procesados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetDocs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// 'g' declarado antes&lt;/span&gt;
  &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vemos que la forma de lanzar la rutina es diferente y ya no usamos la palabra reservada &lt;code&gt;'go'&lt;/code&gt;.&lt;br&gt;
Como argumento, tiene una &lt;em&gt;closure&lt;/em&gt; que devuelve un error, ahi es donde podemos manejarlo como mas nos convenga, sin la necesidad de tener que ornamentar nuestro código.&lt;/p&gt;

&lt;p&gt;Ahora bien, tenemos que hacer algo con los resultados, sino lo perdemos; el alcance (o scope) de la función hace que no podamos accederlo desde "afuera" de la rutina.&lt;/p&gt;

&lt;p&gt;La solución obvia es usar canales, que ya los estudiamos en nuestra lista. Para que sea "thread safe", vamos a usar otro método de los errorgroups. Pasamos al código.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;resChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;DocResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetDocs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// 'g' declarado antes&lt;/span&gt;
  &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;resChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// devuelve el primer err != nil&lt;/span&gt;
    &lt;span class="c"&gt;// handle err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resChan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// cerramos el canal&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;El método &lt;code&gt;Wait()&lt;/code&gt; va a esperar que todas las funciones que llamemos con &lt;code&gt;g.Go()&lt;/code&gt; terminen. En caso de que ninguna tenga errores, siempre va a devolver &lt;code&gt;nil&lt;/code&gt;, sino el que tengamos en nuestro servicio.&lt;/p&gt;

&lt;p&gt;No olviden cerrar el canal una vez que no vamos a escribir mas en él, para evitar memory leaks.&lt;/p&gt;

&lt;p&gt;Como nota, aca no lo repasamos, pero el contexto al ser &lt;em&gt;carrier&lt;/em&gt; de una cancelación subyacente, podemos manejarlo también con un &lt;code&gt;select&lt;/code&gt; para que, si desde algún lado lo dan de baja, no sigamos procesando.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Vemos que es mas sencillo y natural (por así decirlo) manejar rutinas y errores con errGroup. Si bien no tiene todo resuelto en su propio mecanismo, es de fácil acople con otras soluciones como canales, select y demás para que tengamos a disposición todo su potencial. Es muy útil para &lt;em&gt;pipelines&lt;/em&gt; o flujos mas complejos, fácil de leer y hacer debug.&lt;/p&gt;

&lt;p&gt;Podemos encontrar muchas similitudes con los &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-iii-4g6c"&gt;wait groups&lt;/a&gt; y está muy bien, ya que si son parecidos en su objetivo y semántica. Los casos de uso, por el contrario, podemos diferenciarlos y ahi tener mas herramientas a la hora de elegir una solución.&lt;/p&gt;

&lt;p&gt;Espero que les guste y lo puedan usar en sus próximos proyectos.&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>api</category>
    </item>
    <item>
      <title>Concurrencia en Golang IV</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Thu, 27 Apr 2023 01:55:31 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/concurrencia-en-golang-iv-5584</link>
      <guid>https://forem.com/tomaslingotti/concurrencia-en-golang-iv-5584</guid>
      <description>&lt;p&gt;|1. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-go-i-5aao"&gt;Modelo de concurrencia&lt;/a&gt;&lt;br&gt;
|2. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-ii-484m"&gt;Goroutines y canales&lt;/a&gt;&lt;br&gt;
|3. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-iii-4g6c"&gt;Wait Groups&lt;/a&gt;&lt;br&gt;
|4. | &lt;strong&gt;Select y Worker pools&lt;/strong&gt;&lt;br&gt;
|5. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-go-v-4gif"&gt;ErrGroup (error groups)&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Para qué sirve select en Go?
&lt;/h2&gt;

&lt;p&gt;Bueno llegamos a la cuarta entrega, en este caso vamos a esar hablando de la palabra reservada &lt;code&gt;select&lt;/code&gt; y una pequeña implementación en un worker pool (vamos a explicar que es un worker pool).&lt;/p&gt;

&lt;p&gt;Select es un bloque, tiene su sintaxis y su scope comprende todo lo que se ocupa dentro de sus llaves. Su función es el de poner en espera (o wait) a múltiples comunicacions a la goroutine que se está ejecutando, se va a liberar cuando se cumpla alguna de las condiciones que planteamos dentro de nuestro bloque. En otras palabras, en parte de nuestro código que podemos recibir mas de una rutina, es dónde vamos a usar el select.&lt;br&gt;
La sintaxis básica es:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//...&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c"&gt;//...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;u&gt;Nota importate:&lt;/u&gt; El select &lt;strong&gt;bloquea&lt;/strong&gt; la rutina que lo contiene, muchas veces vamos a ver que nuevas goroutines lanzan un &lt;code&gt;select&lt;/code&gt;, tengan esto muy en cuenta y hagan las pruebas necesarias para saber que no van a bloquear la rutina principal.&lt;br&gt;
&lt;u&gt;Nota importante II:&lt;/u&gt; No usen select vacios.&lt;/p&gt;

&lt;p&gt;Ahora para agregarle algo interesante a nuestro &lt;code&gt;select&lt;/code&gt;, dentro del bloque vamos a estar esperando por mensajes que lleguen a los canales que invoquemos. Funciona parecido a la cláusula &lt;code&gt;switch&lt;/code&gt;, pero la condición es quien reciba el mensaje, no hace ningún tipo de &lt;em&gt;pattern matching&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Vamos a una impl real&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;c1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;c2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// enviamos el primer mensaje.&lt;/span&gt;
&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"one"&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="c"&gt;// enviamos el primer mensaje.&lt;/span&gt;
&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"two"&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="c"&gt;// con este select esperamos dos veces, uno por cada&lt;/span&gt;
&lt;span class="c"&gt;// canal. Otra práctica común es tener un for infinito&lt;/span&gt;
&lt;span class="c"&gt;// en una rutina separada para asi no bloquear a la&lt;/span&gt;
&lt;span class="c"&gt;// principal.&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"received"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"received"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aca vemos como en cada case, esperamos leer un mensaje de cada canal. Una vez que ocurra, vamos a salir del bloque.&lt;/p&gt;

&lt;p&gt;Ahora, otro ejemplo que nos sirve como un &lt;em&gt;daemon&lt;/em&gt; en nuestro servicio, que corra cada X tiempo y &lt;em&gt;eternamente&lt;/em&gt; mientras la app este en ejecución.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ticker&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTicker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ticker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                    &lt;span class="c"&gt;//doSomething()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Este código nos asegura que cada una hora vamos a invocar a lo que nosotros le indiquemos. El ticker es un countdown que nos provee el paquete time, muy útil para estos casos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resumen del select
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Bloquea a la rutina que lo esta ejecutando.&lt;/li&gt;
&lt;li&gt;Cuando entra en un case, va a anular a los otros hasta que vuelva a ejecutarse el select (por eso es tan comun verlo en un for{} infinito).&lt;/li&gt;
&lt;li&gt;Suelen ir dentro de una función anónima lanzada en una goroutine.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Worker pools, que son?
&lt;/h2&gt;

&lt;p&gt;sabemos que un pool es una &lt;em&gt;reserva&lt;/em&gt;, en este caso de workers. Ahora en nuestro código tenemos que identificar 3 cosas claras. 1) El pool 2) El worker y 3) El trabajo a realizar.&lt;br&gt;
El objetivo va a ser que podamos procesar trabajo de forma concurrente, los worker que terminan su trabajo, van de nuevo al pool y así tratar de ahorrar recursos, además de tratar de trabajar más eficientemente.&lt;/p&gt;

&lt;p&gt;Vamos a un poco de go.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Definimos lo que va a ser nuestra unidad de trabajo. Podríamos crear otras interfaces más y hacerlo mas &lt;em&gt;polimórfico&lt;/em&gt;. No nos preocupemos por quien lo implementa, sera trabajo del cliente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jobQueue&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt; &lt;span class="c"&gt;// cola de trabajo compartida&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;  &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;
    &lt;span class="n"&gt;jobCh&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;newWorker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;jobCh&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Acá ya tenemos un worker que va a pertener a un pool y escuchar a un canal de unidades de trabajo. El doble channel para el pool es para el registro y otro para activarlo.&lt;br&gt;
La otra función, simplemete actua de constructor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;    &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;
    &lt;span class="n"&gt;workers&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxWorkers&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxWorkers&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;maxWorkers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora tenemos la struct de pool, que contiene el mismo canal que el worker y cuantos workers queremos crear, acompañado de su constructor.&lt;/p&gt;

&lt;p&gt;Tenemos el esqueleto, ahora pasamos a la acción con los métodos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;newWorker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ya se ve algo interesante, por cada worker en que indicamos, vamos a crear uno, asignale el pool que ya teníamos y arrancarlo, veamos de que se trata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// register the actual worker in the queue.&lt;/span&gt;
            &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jobCh&lt;/span&gt;
            &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jobCh&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="c"&gt;// do the actual job here&lt;/span&gt;
                &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para el método start, vamos a registrar el worker y luego con la cláusula select, vamos a esperar a que llegue un trabajo y realizarlo (sin saber que es, pero no nos importa). Todo esto en una nueva rutina por worker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;jobQueue&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;jobChannel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;
                    &lt;span class="n"&gt;jobChannel&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por último, el &lt;code&gt;dispatcher&lt;/code&gt; que va a distribuir la carga de trabajo, cada vez que de la jobQueue, se toma uno disponible del pool y a ese worker (implícito en el job channel) se le asigna el trabajo. La job queue es un recurso compartido.&lt;/p&gt;

&lt;h2&gt;
  
  
  Código en el cliente
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// init the shared data structure.&lt;/span&gt;
    &lt;span class="n"&gt;splanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InitQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// init the dispatcher &amp;amp; keep it listening.&lt;/span&gt;
    &lt;span class="n"&gt;splanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;":8080"&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/jobs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JobHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;JobHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"getting job..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"default"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;work&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;HeavyWork&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;splanner&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddUnit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"job %s %d done"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;HeavyWork&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
    &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;HeavyWork&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"heavy job is running %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Así de simple queda par ael cliente, tiene que implementar la interfaz Unit, con la funcion Job() y agregar la unidad de trabajo con una funcion exportada AddUnit que encola el trabajo. En &lt;code&gt;main&lt;/code&gt; vemos el setup es extremadamente trivial.&lt;/p&gt;

&lt;p&gt;El codigo completo, &lt;a href="https://github.com/tomiok/splanner/"&gt;disponible en github&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Vemos el poder y flexibilidad que nos da el select para orquestar los workers y combinado con el pool, poder despachar rutinas, obtener métricas, etc etc.&lt;br&gt;
No nos olvidemos que hay que estudiarlo, usarlo debidamente y sobre todo, probarlo en muchos escenarios para no llevarnos sosrpresas no gratas en producción.&lt;/p&gt;

&lt;p&gt;Ya saben, si quieren sponsorearme, &lt;a href="https://github.com/sponsors/tomiok"&gt;pueden hacerlo acá!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>go</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Seguridad en Golang</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Tue, 25 Apr 2023 01:49:59 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/seguridad-en-golang-4f29</link>
      <guid>https://forem.com/tomaslingotti/seguridad-en-golang-4f29</guid>
      <description>&lt;h2&gt;
  
  
  Cómo escribir código mas seguro en Go?
&lt;/h2&gt;

&lt;p&gt;En esta ocasion, vamos a ver funciones de &lt;code&gt;hash&lt;/code&gt; y de &lt;code&gt;cifrado/decifrado&lt;/code&gt; con su principal diferencia. Como bonus, una repasada a las funciones pseudo aleatorias del lenguaje.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Intro&lt;/li&gt;
&lt;li&gt;Hash con SHA512&lt;/li&gt;
&lt;li&gt;Usos comunes del hashing&lt;/li&gt;
&lt;li&gt;Cifrado y descifrado&lt;/li&gt;
&lt;li&gt;Usos comunes del cifrado&lt;/li&gt;
&lt;li&gt;Números aleatorios&lt;/li&gt;
&lt;li&gt;Conclusiones&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Intro
&lt;/h3&gt;

&lt;p&gt;Para comenzar, tenemos el paquete Crypto de la &lt;em&gt;stdlib&lt;/em&gt; nos va a proveer el 100% (casi siempre) de las utilidades que necesitamos. Por eso es importante tener a mano su &lt;a href="https://pkg.go.dev/hash"&gt;documentacion oficial&lt;/a&gt; para solventar dudas de implementación y lograr entender los pormenores.&lt;br&gt;
Segundo, pero igual de importante, es que esta operación es "one way", es decir, con el resultado no puedo volver hacia atrás y obtener el valor ingresado.&lt;/p&gt;
&lt;h3&gt;
  
  
  Hash con SHA512
&lt;/h3&gt;

&lt;p&gt;Seguramente habrán visto la sigla SHA en algún lugar de la web, curso, etc, ésta corresponde a Secure Hash Algorithm y viene de larga data acompañándonos. Fue desarrollada en los Estados Unidos en el 2001, por la &lt;a href="https://es.wikipedia.org/wiki/National_Security_Agency"&gt;NSA&lt;/a&gt; y aprobada ese mismo año para su uso, existen variantes del algoritmo, comenzando por SHA-0 (luego vinieron 1, 2 y 3 que es la actual) &lt;strong&gt;y el 512 refiere al tamaño en bits&lt;/strong&gt; de la "salida" o el &lt;em&gt;digest&lt;/em&gt; en inglés.&lt;br&gt;
EL funcionamiento básico es muy simple de explicar sin entrar en tecnisismos: recibe una entrada (arreglo de bytes) de cualquier tamaño y devuelve una palabra de siempre la misma longitud (en este caso 512 bits). Cabe destacar que la entrada puede ser realmente muy grande, segun los datos oficiales es de (2^128-1).&lt;/p&gt;

&lt;p&gt;Ya sabemos como funcionan, ahora un pequño problema que nosotros no nos vamos a encontrar, pero si los involucrados en el desarrollo de estas fantásticas soluciones, fue que al tener un tamaño de salida definido y tanta capacidad para recibir muchos valores, se encontron con la no-grata sorpresa de que destintas entradas tenian como respuesta el mismo resultado, comúnmente llamadas colisiones.&lt;br&gt;
La buena noticia es que a partir de &lt;code&gt;SHA-2&lt;/code&gt;, no se volvieron a encontrar y es algo por lo cual no nos tenemos que preocupar.&lt;/p&gt;

&lt;p&gt;Ahora pasamos un poco al código&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// hashShortVersion simplemente usa la función para del package, devuelve slice de bytes, simple y efectivo.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;hashShortVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;hasher&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sha512&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sum512&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// hasherVersion creamos una interface hash.Hasher, le asignamos una implemntación de sha512 y usamos el método sum de la interface. Nos puede servir para hacer composición o polimorfismo, el resultado es distinto al anterior.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;hasherVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hasher&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hash&lt;/span&gt;
    &lt;span class="n"&gt;hasher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sha512&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sum&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%x"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// binaryVersion convierte a binario nuestros datos.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;binaryVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hasher&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hash&lt;/span&gt;

    &lt;span class="n"&gt;hasher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sha512&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryMarshaler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarshalBinary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como expresan tanto el código y los comentarios, los resultados no son iguales ya que usan métodos/funciones distintas. El &lt;code&gt;MarshallBinary()&lt;/code&gt; no es recomandable usar para guardar los datos en un storage "normal" como bases de datos relacionales, de documentos o archivos porque tiene un formato muy distinto, además de ser ilegible para los humanos y no podemos compararlos con el operador &lt;code&gt;"=="&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usos mas comunes
&lt;/h3&gt;

&lt;p&gt;Decíamos que las funciones hash, tienen como objetivo captar una entrada "digerirla" y devolver un resultado siempre del mismo tamaño. No importa si ingresamos &lt;u&gt;un solo caracter, Don Quijote entero o todo el código fuente de el Kernel de Linux&lt;/u&gt;, la salida tiene siempre el mismo largo. Y como toda función pura, ante la misma entrada, vamos a tener la misma salida, es por eso que el &lt;strong&gt;uso mas común&lt;/strong&gt; es el de garantizar la autenticidad de un software, cuando entregamos el SHA de un &lt;strong&gt;compilado o ejecutable&lt;/strong&gt;, el usuario que lo descarga puede hacer el mismo proceso y validar que haya descargado el mismo que la documentación oficial dice.&lt;br&gt;
Por otra parte, un uso muy común pero que no recomiendo, es para contraseñas, ya que existen tablas con muchisimos datos llamadas &lt;a href="https://auditoriadecodigo.com/rainbow-tables-como-se-crean-y-usan-las-tablas-de-cracking-de-hash-mas-potentes-explicado-facil-o-casi-facil/"&gt;Rainbow tables&lt;/a&gt; que se usan para poder &lt;em&gt;crackear&lt;/em&gt; contraseñas, por lo que no es un caso de uso muy acertado.&lt;/p&gt;

&lt;p&gt;Bueno, hasta acá de &lt;em&gt;hashing&lt;/em&gt;, ahora pasamos al cifrado&lt;/p&gt;


&lt;h3&gt;
  
  
  Cifrado y descifrado
&lt;/h3&gt;

&lt;p&gt;LA principal diferencia con el hashing, es que aca si podemos volver a obtener lo que enviamos en un principio y la segunda, es que ante la misma entrada, podemos no obtener la misma salida (mientras menos colisiones haya, mejor) por sofisticadas funciones matématicas que se denomina &lt;strong&gt;sal&lt;/strong&gt; (o salt en inglés) y es un conjunto de bits aleatorios que su objetivo es el de, justamente, &lt;u&gt;cambiar el resultado ante los mismos valores de entrada.&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;ejemplos en código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenerateFromPassword&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinCost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// puede ser también defaultCost&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encryptedPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plainPassword&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bcrypt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CompareHashAndPassword&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encryptedPassword&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plainPassword&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bueno con este si que no nos podemos quejar, lo fácil y claro que es no deja margen de dudas.&lt;br&gt;
Si prueban imprimir solo el &lt;em&gt;string&lt;/em&gt; resultante varias veces con la misma entrada, pueden ver como obtienen distintos resultados.&lt;/p&gt;
&lt;h3&gt;
  
  
  Usos más comunes
&lt;/h3&gt;

&lt;p&gt;Claramente el uso mas común (hace muchísimos años) es el de ocultar un mensaje y que un receptor pueda interpretarlo. En informática lo vamos a usar extensamente para contraseñas, tokens y valores que el usuario envía y son sensibles.&lt;/p&gt;


&lt;h3&gt;
  
  
  Números aleatorios
&lt;/h3&gt;

&lt;p&gt;Antes de empezar a abordar el tema, no son aleatorios, son pseudo aleatorios y es una definición teórica que pueden ver &lt;a href="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=&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=2ahUKEwjO-e748sP-AhVeq5UCHYXSC7oQFnoECBsQAw&amp;amp;url=https%3A%2F%2Fes.wikipedia.org%2Fwiki%2FN%25C3%25BAmero_pseudoaleatorio&amp;amp;usg=AOvVaw1801fHvnj4wXsJFnI0lnQb"&gt;explicado acá&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En éste código, vemos dos casos de uso muy comunes, el primero es obtener un string aleatorio dado un alfabeto. El parámetro de entrada es uno solo y corresponde a que tan larga debería ser la cadena resultante. Así de simple y sencillo.&lt;/p&gt;

&lt;p&gt;La segunda función, es un poco mas de lo mismo, solo que generamos únicamente números y el parametro de entrada corresponde al límete superior sin incluir, es decir, si ponemos &lt;code&gt;1000&lt;/code&gt;, vamos a generar un número entre &lt;code&gt;0&lt;/code&gt; y &lt;code&gt;999&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GenerateRandomString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letters&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;letters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GenerateRandNum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Int64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Con estos dos &lt;code&gt;snippets&lt;/code&gt; ya tienen para cubrir bastantes casos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusiones
&lt;/h3&gt;

&lt;p&gt;Aprendimos (o repasamos) las principales diferencias entre el hashing y el cifrado, tanto conceptualmente como implementaciones en Golang y sus usos mas frecuentes en la industria, también como el desarrollos académicos.&lt;br&gt;
Por último, cubrimos brevemente que es y como se usa el paquete crypto.Rand y claramente, agregamos un poco de código.&lt;/p&gt;

&lt;p&gt;Ya saben, si quieren sponsorearme, &lt;a href="https://github.com/sponsors/tomiok"&gt;pueden hacerlo acá!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>go</category>
      <category>security</category>
      <category>programming</category>
    </item>
    <item>
      <title>Handlers con timeouts en Go</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Sat, 24 Dec 2022 23:45:03 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/handlers-con-timeouts-en-go-3418</link>
      <guid>https://forem.com/tomaslingotti/handlers-con-timeouts-en-go-3418</guid>
      <description>&lt;p&gt;En algunas oportunidades, vamos a necesitar un comportamiento &lt;strong&gt;muy&lt;/strong&gt; determinístico en nuestras APIs, ya sea porque el negocio así lo requiere o los clientes. Tal vez, un comportamiento que se mantenga alejado de cualquier sorpresa, puede ser el máximo de duración que le queremos dejar como ventana para que un respuesta sea entregada, en caso de excederlo, ahora si como el título lo dice, devolvemos un &lt;strong&gt;timeout&lt;/strong&gt;... pero, qué es un timeout?&lt;br&gt;
En principio sabemos que contamos con 2 estados para representarlo, pero no se parecen mucho ya que están en &lt;em&gt;centenas&lt;/em&gt; distintas, unos es &lt;strong&gt;408 request timeout&lt;/strong&gt; y el otro es &lt;strong&gt;504 Gateway timeout&lt;/strong&gt;.&lt;br&gt;
Si leemos un poco las especificaciones, ninguno de los dos &lt;em&gt;nos calza justo&lt;/em&gt; para lo que queremos, el 408 nos dice que el cliente "se tardó demasiado para enviar su request", desde la RFC dice lo siguiente:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Y para su contraparte del lado del servidor:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The server was acting as a gateway or proxy and did not receive a timely response from the upstream server.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Entonces, para la responder la pregunta, concluimos que un timeout es que esperamos demasiado por algo, y no sucedió, ademas, lo consideramos un error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cómo hacemos nuestras funciones de Timeout?
&lt;/h3&gt;

&lt;p&gt;En los lenguajes de programación modernos, encontramos built-in algunas formas de manejar estos casos de uso. En Golang, por ejemplo el paquete &lt;code&gt;context&lt;/code&gt; tiene &lt;em&gt;constructores&lt;/em&gt; para crear uno que expire y se cancele después de cierto tiempo.&lt;/p&gt;

&lt;p&gt;Dentro del paquete net/http también nos encontramos con muchos timeouts como por ejemplo en la struct &lt;code&gt;http.Client&lt;/code&gt; para hacer requests y &lt;code&gt;http.Server&lt;/code&gt; es otra que tampoco se queda afuera de tener este tipo de configuración.&lt;/p&gt;

&lt;p&gt;Por ahora, tenemos: context, http.Client y Server, servidores TCP y UDP, etc. Podemos resumir que siempre que haya una conexión hacia fuera (ya sea cliente o servidor) vamos a poder configurar un timeout.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cómo nos sirven en los web handlers?
&lt;/h3&gt;

&lt;p&gt;Antes, debemos aclarar que es un &lt;strong&gt;middleware&lt;/strong&gt;, en cualquier lenguaje, ya que es un concepto y no una implementación específica de Golang. &lt;/p&gt;

&lt;p&gt;Entonces, decimos que son funciones con la misma firma que un handler (o controlador web), que recibe los mismos parámetros  para operar como una petición HTTP. Al ser iguales, nos permite ejecutarlo previamente de una forma sencilla y pre-ejecutar operaciones que nos ayuden a nuestro negocio. Un claro ejemplo son validaciones de token JWT, agregar request ID unicos, sumarle datos al contexto (esto si es mas estilo &lt;em&gt;gopher&lt;/em&gt;).&lt;br&gt;
En nuestro caso, vamos a tener un middleware que se encargue de reemplazar el contexto, por otro que tenga un timeout, para que no tarde mas de tanto tiempo y si no, falla. Nos va a ayudar a garantizar un tiempo de respuesta de máxima, por las buenas &lt;em&gt;o por las malas&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo llevamos a código
&lt;/h2&gt;

&lt;p&gt;Como middleware, podemos usar &lt;em&gt;uno que ya existe&lt;/em&gt; y está dentro del paquete http, es &lt;code&gt;http.Timeout&lt;/code&gt; y dentro de su firma, vamos a pasarle un &lt;code&gt;http.Handler&lt;/code&gt;, &lt;strong&gt;el tiempo de espera que vamos a soportar&lt;/strong&gt; y por último (este no me gusta mucho) un mensaje como string, donde nos quita un poco de flexibilidad, a mi entender, &lt;code&gt;[]byte&lt;/code&gt; nos daría un espectro mas amplio a la hora de retornar los valores.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Podemos implementarlo como un wrapper general a todo el multiplexer y que todos ejecuten el middleware, este tiene como ventaja que escribimos una sola vez, pero perdemos granularidad.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;//....&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;muxWithMiddleware&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimeoutHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"timeout!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;muxWithMiddleware&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Por último, tenemos otro camino, para tener un control espercífico en cada handler que expongamos.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;helloHandler&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimeoutHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wrapHandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello with timeout!"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;})),&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;helloHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;wrapHandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;wrapped&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapped&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Vemos la flexibilidad que tenemos para exponer funciones en un servior web que tenemos en Golang. Siempre nos da muchas facilidades y opciones, a su vez, puede ser un poco confuso porque no sabemos bien cual usar. Como pequeño consejo, no nos &lt;em&gt;fritemos&lt;/em&gt; la cabeza pensando y comparando, tan solo elijamos una con un análisis superficial y despues nos queda el aprendizaje.&lt;/p&gt;

&lt;p&gt;Para cerrar el tema técnico, estamos re-utilizando una funcion de la stdlib de Go, por lo que no es necesario que nostros pensemos esa lógica, también, muchos de los Frameworks web como Echo, Gin y Fiber (seguramente entre varios otros) ya traen sus middleware de timeout y es de una implementacion muy similar a la que acabamos de ver.&lt;/p&gt;

&lt;p&gt;Espero que les haya gustado la explicación! nos vemos dentro de poco y cualquier tema que quieran que tratemos lo pueden dejar en comentarios.&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Concurrencia en Golang III</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Wed, 07 Dec 2022 22:04:50 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/concurrencia-en-golang-iii-4g6c</link>
      <guid>https://forem.com/tomaslingotti/concurrencia-en-golang-iii-4g6c</guid>
      <description>&lt;p&gt;|1. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-go-i-5aao"&gt;Modelo de concurrencia&lt;/a&gt;&lt;br&gt;
|2. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-ii-484m"&gt;Goroutines y canales&lt;/a&gt;&lt;br&gt;
|3. | &lt;strong&gt;Wait Groups&lt;/strong&gt;&lt;br&gt;
|4. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-iv-5584"&gt;Select y Worker pools&lt;/a&gt;&lt;br&gt;
|5. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-go-v-4gif"&gt;ErrGroup (error groups)&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  WaitGroups, que son y para qué sirven?
&lt;/h2&gt;

&lt;p&gt;Siempre me gusta comenzar los temas respondiendo estas dos preguntas, porque nos da un panorama general de que problemas nos ayuda a resolver y cuándo es mejor usar ésta tecnología.&lt;/p&gt;

&lt;p&gt;Los &lt;strong&gt;WG&lt;/strong&gt; son estructuras que nos permiten "alojar" rutinas (la cantidad que querramos) y -lo mas importante- poder esperar a que todas terminen. En resumen, es un mecanismo de sincronización de go-rutinas, donde podemos ejecutar todas las que sean necesarias y quedar a la espera a que la totalidad terminen.&lt;br&gt;
Es muy útil cuando queremos &lt;em&gt;paralelizar&lt;/em&gt; un trabajo pero tratándolo como una unidad, que una vez terminada, sigue el flujo normal de trabajo.&lt;/p&gt;

&lt;p&gt;Para terminar la introducción, la struct de WaitGroup se encuentra en el paquete &lt;code&gt;sync&lt;/code&gt; de la stdlib, no tenemos que importar nada.&lt;/p&gt;
&lt;h2&gt;
  
  
  Como se usan los wait groups?
&lt;/h2&gt;

&lt;p&gt;Tenemos 3 métodos básicos que nos van a dar soporte a nuestra operación.&lt;/p&gt;

&lt;p&gt;Vamos a mejorar el ejemplo que dimos en el post anterior, donde usábamos (mal) la función &lt;code&gt;time.Sleep()&lt;/code&gt; para esperar que la goroutine termine. Ahora vamos a mostrar una forma correcta de hacer el mismo trabajo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;doWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"exiting..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;doWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta &lt;strong&gt;si&lt;/strong&gt; es la forma correcta de ejecutar un hello world en una goroutine. Vamos paso a paso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;definimos la variable wg que es de tipo sync.WaitGroup, yo aconsejo declararla así para mejor lectura, aunque &lt;code&gt;wg := sync.WaitGroup{}&lt;/code&gt; también es correcto.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dentro de main, donde lanzamos la rutina con el prefijo &lt;code&gt;go&lt;/code&gt; (eso ya lo sabemos hacer), tenemos el método Add(), que tiene como parámetro de entrada un entero (se llama delta) y ahi le vamos a especificar con una precisión absoluta, cuantas goroutines se va a agregar a la lista de espera, la misma cantidad que se agreguen, van a ser las que terminen.&lt;br&gt;
En caso de ejecutar muchas goroutines o que se lancen dentro de un bucle, en lugar de poner el numero exacto podemos igualmente siempre agregar 1; Por ejemplo:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;doWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entonces, independientemente de la cantidad de &lt;code&gt;ints&lt;/code&gt; vamos a agregar siempre de a una.&lt;br&gt;
Acá otra recomendación para Add(), y es que admite &lt;strong&gt;números negativos&lt;/strong&gt;, para decrementar la cantidad en espera, yo NO lo recomiendo usar a menos que sea un caso de uso exacto, puede llevar a problemas cuyas soluciones sean muy difíciles de encontrar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Vemos también que a la función doWork, le pasamos la dirección de memoria de la estructura wg. Esto es importante porque estrictamente queremos esa referencia y no modificar una copia, suele ser un error normal cuando empezamos a usar esta sincronización, este bien atentos a recibir punteros y pasar direcciones de memoria con '&amp;amp;'.&lt;br&gt;
En doWork, invocamos a &lt;code&gt;Done()&lt;/code&gt;, puede usarse con la palabra reservada 'defer' para que no repetirnos en caso de tener varias salidas o &lt;code&gt;return&lt;/code&gt; y como su nombre lo indica, &lt;code&gt;Done()&lt;/code&gt; lo debemos llamar cuando el trabajo está terminado. Internamente va a descontar en una unidad a la lista de espera y marcar esa tarea como finalizada.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Por último, el método &lt;code&gt;Wait()&lt;/code&gt;, que va a detener el control del programa hasta que el contador de la lista de espera de 0( cero) y todas las rutinas hayan ejecutado la función &lt;code&gt;Done()&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Los WG son un mecanismo excelente para garantizar completitud de N cantidad de goroutines, fácil de implementar y probar, ademas de que la encontramos en la stdlib, como la gran mayoría de cosas que vamos a ver en estos artículos.&lt;/p&gt;

&lt;p&gt;Ya saben, si quieren sponsorearme, &lt;a href="https://github.com/sponsors/tomiok"&gt;pueden hacerlo acá&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>api</category>
      <category>go</category>
      <category>programming</category>
      <category>c</category>
    </item>
    <item>
      <title>Concurrencia en Golang II</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Thu, 01 Dec 2022 20:40:55 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/concurrencia-en-golang-ii-484m</link>
      <guid>https://forem.com/tomaslingotti/concurrencia-en-golang-ii-484m</guid>
      <description>&lt;p&gt;|1. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-go-i-5aao"&gt;Modelo de concurrencia&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;|2. | Goroutines y canales&lt;/strong&gt;&lt;br&gt;
|3. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-iii-4g6c"&gt;Wait Groups&lt;/a&gt;&lt;br&gt;
|4. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-iv-5584"&gt;Select y Worker pools&lt;/a&gt;&lt;br&gt;
|5. | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-go-v-4gif"&gt;ErrGroup (error groups)&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Goroutines e hilos recap
&lt;/h2&gt;

&lt;p&gt;En el post anterior, vimos brevemente una comparación entre las goroutines y los threads, que no va mucho más allá, pero si para refrescar un poco la memoria vamos a repasarla:&lt;br&gt;
Las rutinas: Son más livianas ( &amp;lt; 2 kb) por que no necesitan tanto espacio en RAM ni los datos en el registro para que el sistema operativo pueda identificarlo.&lt;br&gt;
Son 100% manejadas por el runtime de Go.&lt;br&gt;
Se comunican por medio de canales con otras rutinas.&lt;br&gt;
Los Hilos: Son propiedad del sistema operativo.&lt;br&gt;
Pesan alrededor de 1mb, tienen que mantener muchos datos para que el sistema operativo los identifique y pueda saber su estado.&lt;br&gt;
La comunicación entre dos hilos es un proceso costoso, si bien excede a este post, pueden buscar más información buscándolo como "Context Switch".&lt;/p&gt;
&lt;h2&gt;
  
  
  Cómo ejecutar una rutina en Go
&lt;/h2&gt;

&lt;p&gt;El lenguaje nos ofrece una mecánica muy simple que es agregar la palabra reservada go por delante de la función o método que queremos ejecutar.&lt;br&gt;
package main&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claramente si ejecuta ese código, no va mostrar nada, o si, no lo se. Lo que si se es que no podemos garantizar nada.&lt;br&gt;
¿Por qué no podemos ver el resultado?&lt;br&gt;
La respuesta es fácil, pero por detrás se oculta toda la lógica de procesamiento de rutinas. Primero, hay que destacar que siempre al menos vamos a correr una rutina, cada vez que ejecutemos un programa en Go. Esta es la rutina principal que viene con la función main. Cada sentencia go que agreguemos, va a sumar una más a la existente.&lt;br&gt;
Ya sabiendo que tenemos siempre una rutina (main) y que el runtime es quien se dedica, en parte, a dar el lugar de ejecución y mantener el ciclo de vida de las rutinas, es ahí donde tenemos la certeza de no garantía de ejecución; en otras palabras si al runtime se le ocurre correr la rutina con el Print del "hello world" puede que lo veamos en pantalla, aunque sigue siendo un proceso no determinista.&lt;br&gt;
Vamos a plantear una solución rápida, usando la lib de golang, que es la funcion Sleep(), para que dentro de un tiempo razonable, le damos la oportunidad al scheduler que nos ejecute la goroutine y veamos el mensaje en pantalla (recuerden nunca hacer esto en un programa productivo, jamás)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="s"&gt;"fmt"&lt;/span&gt;
         &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listo, ya le dimos 5 segundos, más que suficiente para que todo comience y termine.&lt;br&gt;
Más adelante vamos a ver cómo podemos usar waitgroups, que es el mecanismo correcto para asegurarnos la finalización de los procesos.&lt;/p&gt;
&lt;h2&gt;
  
  
  Anatomía de los canales
&lt;/h2&gt;

&lt;p&gt;Un canal es un tipo de dato nativo de Golang. se declara con la palabra reservada chan y tenemos que especificarle "de que va a ser ese canal", además tenemos otro dato opcional que especifica el tamaño (o buffer) del canal, es decir, que tantos mensajes puede tener en su buffer hasta que la escritura sea bloqueante.&lt;br&gt;
Se crean con la función interna &lt;strong&gt;new()&lt;/strong&gt;.&lt;br&gt;
Un ejemplo podría ser:&lt;br&gt;
&lt;code&gt;ch := make(chan string) // sin buffer&lt;/code&gt;&lt;br&gt;
&lt;code&gt;bufCh := make(chan string, 5) // con un buffer de 5 mensajes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;La principal &lt;strong&gt;diferencia&lt;/strong&gt; radica en el bloqueo a la hora de la lectura/escritura. Empecemos con &lt;em&gt;los channels sin buffer o sin capacidad definida.&lt;/em&gt;&lt;br&gt;
Repasamos qué es un bloqueo a nivel de goroutine, que es algo grave y de lo que el programa no va a poder recuperarse fácilmente. En esencia, la rutina va a quedar bloqueada, hasta que pueda ser desbloqueada (ya sea con una escritura o lectura del canal para que libere al canal y la rutina que no pudo operar), pero en caso de que las "rutinas que iban a desbloquear", hayan terminado, estamos en la presencia de un deadlock, y ahi si la ejecución de nuestro programa se detiene.&lt;br&gt;
&lt;strong&gt;Para la escritura&lt;/strong&gt;, va a ser siempre blocking, es decir que se va a completar la operación cuando la lectura se lleva a cabo, es la razón por la que los canales sin capacidad definida, tienen que escribirse en goroutines separadas a las de lectura.&lt;br&gt;
&lt;strong&gt;Para la lectura&lt;/strong&gt; también es blocking mientras no haya mensajes para leer. Entonces, si volvemos a la definición de bloqueo, una rutina podría quedar bloqueada si no tenemos bien desarrollado que primero escriba y después acceda a leer. En caso de que nos quede al revés, tenemos un deadlock.&lt;br&gt;
Por eso decimos que los canales unbuffered son sincrónicos porque entre los dos, deben esperar ambas operaciones sucedan para realizar la comunicación.&lt;br&gt;
&lt;em&gt;Ahora vamos con los buffered:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Para la escritura, van a ser non-blocking a menos que el buffer esté lleno, en ese caso vamos a tener que "esperar" que otra rutina lea un mensaje para que salga del buffer, y ahí volvemos a tener espacio para uno más. En el ejemplo de arriba, en caso de que nadie los lea, el mensaje numero 6, no se podría efectivizar y la rutina quedaría bloqueada.&lt;br&gt;
Para la lectura, también va a ser non-blocking a menos que el canal esté vacío.&lt;br&gt;
Por eso decimos que la comunicación es asíncrona para los canales con capacidad definida.&lt;/p&gt;
&lt;h2&gt;
  
  
  Sintaxis para leer y escribir
&lt;/h2&gt;

&lt;p&gt;Vamos directo al código para escribir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;DoCalc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// tomamos un valor de la db&lt;/span&gt;
   &lt;span class="c"&gt;// La sintaxis para trabajar en el canal es con el operador "&amp;lt;-".&lt;/span&gt;
   &lt;span class="c"&gt;// Nos indica la dirección en la que se escribe el valor, por ej (ch &amp;lt;- "value"), vamos a escribir sobre canal, le estamos mandando un valor.&lt;/span&gt;
   &lt;span class="c"&gt;// Por otro lado, el _channel_ puede asignar valores a variables, estructuras, etc, dependiendo de lo que contenga, por ejemplo (value := &amp;lt;- ch), decimos que leemos de un canal.&lt;/span&gt;
   &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para la lectura es similar, aunque tenemos variantes&lt;br&gt;
Podemos hacerlo con el operador, nos va a traer el dato, pero además podemos recibir un tipo bool, para saber si realmente fue una lectura exitosa o si el canal estaba cerrado, tenemos un zero value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;
    &lt;span class="c"&gt;// donde v es el valor del canal y ok nos permite saber si la lectura fue exitosa o no.&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Es el mismo ejemplo pero sin el OK, no es necesario pedirlo. En algunos casos más recomendado que en otros.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es importante saber que tipo de canal vamos a usar (con capacidad o sin capacidad) y eso nos va a ayudar a estructurar mejor los mecanismos de lectura/escritura para evitar bloqueos. Aunque la mayoría se pueden solucionar con tests, pero siempre es conveniente tener los conceptos claros para saber lo que estamos haciendo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Tenemos las goroutines que se ejecutan fácilmente con la keyword go y una función o clausura, es rutina corre sobre un hilo (thread) del sistema operativo. La rutina principal es Main y siempre se ejecuta, cuando esta se corta, le comunica al sistema operativo si fue con código 0 (sin errores) o distinto de 0 dependiendo del error ocurrido.&lt;br&gt;
Por otro lado, tenemos los canales que es el medio de comunicación de las rutinas. también es un tipo de dato &lt;em&gt;nativo&lt;/em&gt; de Go, o sea que no tenemos que importar nada de afuera. Los canales pueden tener o no un tamaño y eso modifica la forma en que bloquea la lectura/escritura.&lt;br&gt;
Para terminar, recuerden que es importante saber la naturaleza del problema y si es necesario usar más de un hilo de ejecución, y en caso de necesitarlos, también debemos saber que si los recursos están bien manejados, podemos tener un gran número de rutinas en un &lt;em&gt;hardware&lt;/em&gt; que no sea el más caro o grande.&lt;/p&gt;

&lt;p&gt;Si te gusto el contenido, podes sponsorearme &lt;a href="https://github.com/sponsors/tomiok"&gt;aca&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Concurrencia en Golang I</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Wed, 19 Oct 2022 20:09:50 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/concurrencia-en-go-i-5aao</link>
      <guid>https://forem.com/tomaslingotti/concurrencia-en-go-i-5aao</guid>
      <description>&lt;p&gt;En esta serie de posts, vamos a estar explicando varios temas relacionados a la concurrencia en Golang, desde cómo está pensada en el &lt;em&gt;runtime&lt;/em&gt; hasta implementar patrones para resolver problemas.&lt;br&gt;
En estas series, vamos a repasar los siguientes conceptos:&lt;/p&gt;

&lt;p&gt;|1.   | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-go-i-5aao"&gt;Modelo de concurrencia&lt;/a&gt;&lt;br&gt;
|2.   | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-ii-484m"&gt;Goroutines y canales&lt;/a&gt;&lt;br&gt;
|3.   | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-iii-4g6c"&gt;Wait Groups&lt;/a&gt;&lt;br&gt;
|4.   | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-golang-iv-5584"&gt;Select y Worker pools&lt;/a&gt;&lt;br&gt;
|5.   | &lt;a href="https://dev.to/tomaslingotti/concurrencia-en-go-v-4gif"&gt;ErrGroup (error groups)&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Ya que esta es la primera entrega, acá vamos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modelo de concurrencia
&lt;/h2&gt;

&lt;p&gt;A diferencia de otros lenguajes, en Go tenemos goroutines (go rutinas) que nos permiten &lt;em&gt;multiplexar&lt;/em&gt; trabajo por sobre un hilo de ejecución. Si bien eso suena &lt;em&gt;a nada especial&lt;/em&gt;, la idea por detrás es que no vamos a crear Threads (hilos) directamente en el sistema operativo, sino que el &lt;em&gt;runtime scheduler&lt;/em&gt; se va a hacer cargo de crear rutinas que vivan en un thread, de esa manera vamos a tener una relación MxN con hilos y rutinas. Por cada Thread vamos a poder ejecutar N goroutines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftio0qrbdgmdu1tmzylqv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftio0qrbdgmdu1tmzylqv.png" alt="MxN threads"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Communicating Sequential Processes (o SCP) es el modelo teórico escrito y documentado por el científico Tony Hoare y donde Go basa su estructura principal. El &lt;em&gt;paper&lt;/em&gt; no lo vamos a explicar en profundidad, primero por su complejidad y segundo porque Go solo toma algunos conceptos, no todo, pero pueden revisarlo &lt;a href="https://dl.acm.org/doi/10.1145/359576.359585" rel="noopener noreferrer"&gt;aca&lt;/a&gt; si estan muy interesados en ver el corazón del proyecto, pero resumiendolo bastante, podemos concluir que es posible resolver concurrencia con dos primitivos que son:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Entrada&lt;/li&gt;
&lt;li&gt;Salida&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En un flujo donde podemos dejar plasmada de forma atómica una rutina, decimos que una entrada es información que puede &lt;em&gt;sufrir&lt;/em&gt; un proceso para tener una salida. O sea una unidad básica de trabajo.&lt;br&gt;
Si reunimos estos puntos, en una pieza de software quiere decir que también lo podemos &lt;em&gt;llevar&lt;/em&gt; a un proceso de ejecución concurrente.&lt;/p&gt;

&lt;p&gt;Dijimos que solo tomó prestados algunos conceptos, del paper inicial para el desarrollo del modelo de concurrencia y dentro de esa abstracción conceptual vemos el resultado tangible que se expresa en la semántica de Go con 2 mecanismos clave: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Goroutines (rutinas)&lt;/li&gt;
&lt;li&gt;Canales
Y capaz (esto a mi entender solamente) el &lt;code&gt;select&lt;/code&gt; como herramienta built-in para sincronizar.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Go Scheduler
&lt;/h2&gt;

&lt;p&gt;Es una parte muy importante del runtime de Go, es código C estáticamente &lt;em&gt;linkeado&lt;/em&gt; dentro del binario que vamos a ejecutar. Sabemos que Go en su fase de compilación, nos genera un único archivo ejecutable en la máquina contenedora. Dentro del runtime van a coexistir las llamadas al sistema operativo como por ejemplo, creación de threads.&lt;br&gt;
Dentro del Scheduler, una sección muy importante es el goroutine scheduler, que es quien se encargue de el procesamiento de las rutinas, conozca de su ciclo de vida y sea quien decida qué rutina ejecutar en cada turno, es por eso que nosotros como desarrolladores no podemos garantizar el orden de ejecucion y/o finalizacion de las goroutines.&lt;/p&gt;

&lt;p&gt;En esta imagen vemos como es la comunicación desde el ejecutable para con el Kernel del SSOO.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwuvru1gwhouzfuxk89d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwuvru1gwhouzfuxk89d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Las goroutines son similares a los hilos del SSOO pero mucho más livianas ya que ocupan menos recursos y son manejadas por Go, en cambio los threads son propiedad del SSOO y su implementación cambia entre por ejemplo Windows y MacOS.&lt;br&gt;
Otra diferencia es la comunicación entre ellos, para que dos goroutines se comuniquen, existe la herramienta built-in en Go conocida como &lt;strong&gt;channels&lt;/strong&gt;, en cambio para los threads no existe algo nativo que sirva con el mismo propósito.&lt;br&gt;
El tiempo que tardan en crearse también es muy distinto, ya que un thread necesita un stack de un MB de memoria en un Kernel std y muchos valores de los registros asociados para poder idenficarlo, mientras que una goroutine tiene un espacio en memoria de &amp;lt; 2 kb.&lt;/p&gt;

&lt;p&gt;Aun así, las rutinas de Go están basadas en los threads, corren si o si en uno de ellos, es decir, no tenemos goroutinas en el sistema operativo, por eso podemos tener N rutinas por cada thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusiones
&lt;/h2&gt;

&lt;p&gt;Como conclusión en alto nivel, tenemos por un lado, el modelo de concurrencia de Golang está basado en entrada, proceso y salida, muy simple pero no menos efectivo.&lt;/p&gt;

&lt;p&gt;Go tiene 2 técnicas para manejar concurrencia, goroutines y canales. Tiene varios otros más para sincronización, que ya vamos a ir revisando.&lt;/p&gt;

&lt;p&gt;Goroutines y Threads se parecen en muchos aspectos, pero no son lo mismo. Las rutinas viven en los threads y por esa razón (principalmente) son mucho más livianas. En un programa Go podemos tener M threads X N goroutines (por ejemplo 2 threads y 100 goroutines). Cómo vemos en la primera imagen.&lt;/p&gt;

&lt;p&gt;Por último, la arquitectura de Go que al compilar, además de todo nuestro código en el programa, va a hacer un &lt;em&gt;static link&lt;/em&gt; de varias cosas más, entre ellas el runtime que va a ser quien se encargue del manejo pesado de las goroutines. Como su ciclo de vida, ejecución, "turnos", etc, y también otras operaciones con el sistema operativo.&lt;/p&gt;

&lt;p&gt;Espero que les guste y hasta la próxima, con la siguiente entrega.&lt;/p&gt;

&lt;p&gt;PS: &lt;a href="https://github.com/sponsors/tomiok" rel="noopener noreferrer"&gt;sponsoreame aca&lt;/a&gt; si te gusto el contenido&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>JWT y Golang</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Sat, 01 Oct 2022 17:37:34 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/jwt-y-golang-4opp</link>
      <guid>https://forem.com/tomaslingotti/jwt-y-golang-4opp</guid>
      <description>&lt;p&gt;Bien sabemos lo complicado que es cubrir el 100% de los casos de uso cuando hablamos de registro de usuario, autorización y autenticación. Eternas discusiones que nos consumen mucho tiempo y recursos para siempre dejar espacios en blanco que con el tiempo serán subsanados con nuevas versiones de nuestros servicios encargados de estas acciones. Siempre recomiendo, para cada desarrollo donde servidor y cliente están separados, tener un mecanismo basado en Tokens (puede ser JWT, puede ser cualquier otro) para garantizar la autenticidad de las peticiones.&lt;/p&gt;

&lt;h2&gt;
  
  
  JWT y REST
&lt;/h2&gt;

&lt;p&gt;Siempre leímos que en &lt;strong&gt;REST&lt;/strong&gt; cada petición tiene que ser independiente a su predecesora y sucesora, lo cual es &lt;em&gt;falso&lt;/em&gt; para sistemas que requieran autenticación, que a su vez, corresponden a la gran mayoría de los que usamos en nuestras PCs y teléfonos; es muy difícil imaginar poder hacer una transferencia bancaria sin autenticarse primero o querer publicar una entrada en un blog sin antes dejar mis credenciales.&lt;/p&gt;

&lt;p&gt;Entonces, tenemos una primera petición bien conocida, que es proveer nuestra identidad, sin importar de qué manera, SSO con Google, GitHub, email y password o biometría, le tenemos que dar &lt;em&gt;algo&lt;/em&gt; para que el sistema confíe en que somos nosotros. En un futuro, voy a intentar redactar modelos de autenticación más sofisticados para servidores web.&lt;/p&gt;

&lt;p&gt;Una vez validadas las credenciales, el servidor nos otorga una llave para nuestras sucesivas peticiones dentro del mismo dominio, que suele ser un &lt;strong&gt;token&lt;/strong&gt; (un string o cadena de caracteres), con un formato específico que ambos entienden, firmado con un algoritmo (que ambos entienden) e información adicional que puede ser cualquier cosa, aunque se recomienda altamente no dejar nada sensible o que pueda llevarnos a conocer más acerca de quién era -el dueño- del Token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Morfología del JWT
&lt;/h2&gt;

&lt;p&gt;Sabemos por sus siglas en inglés, qué es JSON, es Web y es un Token, a su vez, cuenta con una estructura bien determinada en la cual se basa el mecanismo. Consta de 3 partes separadas por un punto y cada una de ellas contiene datos específicos, las librerías de los lenguajes nos ayudan a formar JWTs correctos y seguros. También, estas tienen una estructura JSON y están &lt;em&gt;encodeadas&lt;/em&gt; en &lt;strong&gt;Base64&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Éstas partes son:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Headers&lt;/strong&gt; -&amp;gt; dónde se encuentran el algoritmo de encriptación usado y el tipo de  token.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Payload&lt;/strong&gt; -&amp;gt; acá, se encuentran los datos que queremos transportar del usuario, el campo "sub" (de subject) es donde comúnmente se encuentra un identificador único. Podemos agregar los campos que necesitemos pero es muy importante no agregar nada sensible por un simple hecho; en caso de que el token quede comprometido, la información es totalmente accesible, ya que solo está en formato de Base64 (al igual que las demás partes).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Signature&lt;/strong&gt; -&amp;gt; Este segmento valida la firma a la hora de verificar el token y si estaba sellado con una contraseña, debemos utilizar la misma, caso contrario el token va a ser detectado como inválido y por consiguiente, el cliente no podrá consumir el recurso seguro.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esta imagen es de la web &lt;a href="https://jwt.io" rel="noopener noreferrer"&gt;jwt.io&lt;/a&gt; donde pueden practicar como crear uno y validarlo.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvymgg3rxrk0iu049b0zp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvymgg3rxrk0iu049b0zp.png" alt="sitio web de jwt.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Otros &lt;em&gt;claims&lt;/em&gt; (campos) importantes en el payload de JWT son los de "iat" y "exp" que además del "sub" deben viajar siempre y corresponden a &lt;em&gt;issued at&lt;/em&gt; (cuando se firmó) y &lt;em&gt;expires at&lt;/em&gt; (cuando vence). Es muy común en sitios web ver el check de &lt;em&gt;remember me&lt;/em&gt;, la gran mayoría de las veces esto es para firmar el token con un exp mucho mayor que si no estuviese checkeado.&lt;/p&gt;


&lt;h2&gt;
  
  
  Cómo lo hago en Golang?
&lt;/h2&gt;

&lt;p&gt;En Go tenemos librerías muy fáciles de usar, mi consejo es usarlo como servicio e inyectar cuando sea necesario, para después usarlo como middleware, así su uso queda muy natural y desacoplado a la lógica de negocios.&lt;/p&gt;

&lt;p&gt;Acá vemos para firmar el token, no necesitamos casi nada extra aparte de "&lt;a href="//github.com/golang-jwt/jwt"&gt;github.com/golang-jwt/jwt&lt;/a&gt;", solo un secreto para firmar el token y los claims, que además de los estándar, podemos agregar los que necesitemos. Es importante tener en cuenta el tag json para que queden con el formato esperado.&lt;/p&gt;

&lt;p&gt;La expiración del token queda grabada en esta firma también.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Ahora vemos como usarlo como un middleware en los web handlers y declarando como servicio&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;y con estos simples pasos ya podemos agregarlo a cualquier ruta como middleware, en caso de que estemos usando la &lt;em&gt;std lib&lt;/em&gt; de Golang, en caso de usar algún framework web com o Gin, Fiber o Echo, vamos a tener que modificar un poco la firma, pero de lo contrario, ya está listo para ser implementado.&lt;/p&gt;

&lt;p&gt;Si les gustó el contenido, &lt;a href="https://github.com/sponsors/tomiok" rel="noopener noreferrer"&gt;me pueden sponsorear aca&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>security</category>
      <category>api</category>
    </item>
    <item>
      <title>Qué es el Bloom Filter?</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Tue, 13 Sep 2022 16:48:56 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/que-es-el-bloom-filter-4ddm</link>
      <guid>https://forem.com/tomaslingotti/que-es-el-bloom-filter-4ddm</guid>
      <description>&lt;p&gt;Hablamos de una estructura de datos no tan común pero que tiene casos de uso interesantes, ademas es una buena opción cuando queremos reducir el uso de memoria. Como es un filtro, la respuesta esperada es si por lo que estoy preguntando, se encuentra o no guardado en nuestros sistemas.&lt;/p&gt;

&lt;p&gt;Con esto en mente, tenemos que saber que es una estructura probabilística, con dos resultados posibles, estos son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Seguro que no ❌​&lt;/li&gt;
&lt;li&gt;Probablemente si 🤞​&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si nos dice que no, es que no está y eso es seguro, pero no puede garantizar que sí, entonces si la respuesta es &lt;em&gt;probablemente si&lt;/em&gt; vamos a tener que asegurarnos yendo a verificar por segunda vez, pero a otro lugar, no al filtro. Esto se puede dar por colisiones en funciones hash y también en que, al reducir el espacio en memoria, las colisiones van a estar presentes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ahora vemos como funciona
&lt;/h2&gt;

&lt;p&gt;Hablamos de probabilidades, hashes, colisiones y demás, vamos a explicar con un caso concreto.&lt;/p&gt;

&lt;p&gt;Supongamos que &lt;a href="//dev.to"&gt;dev.to&lt;/a&gt; no quiere recomendarte un post que ya leíste en el ultimo tiempo, entonces, vamos a ir cargando los posts vistos en el filtro de una manera particular, que ahora detallamos.&lt;/p&gt;

&lt;p&gt;Para nuestro filtro vamos a usar un arreglo (slice si sos gopher) con un numero que sepamos, en este caso 100, así no crece indiscriminadamente porque la idea principal es mantener nuestro uso de memoria, bajo. Usamos bool para representar 0 y 1.&lt;br&gt;
Cada función de hash (podemos usar varias, recomiendo fuertemente más de una) va a devolver un numero entero como resultado y cada entrada va a ser representada por n números siendo n la cantidad de funciones de hash que usemos. Después todos los resultados van a traducirse en que ese mismo indice, va a quedar en true. Por ejemplo si tenemos un slice de 10 de bool y las tres funciones nos devuelven 2, 3 y 6 nos queda algo así:&lt;br&gt;
&lt;code&gt;[f][f][✅​][✅​][f][f][✅​][f][f][f]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Entonces...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="c"&gt;//100 para tener una buena distribución&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora las funciones hash&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;h1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;h2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;h3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si bien son &lt;em&gt;placeholders&lt;/em&gt;, la idea es que tome cualquier valor y devuelva un entero que esté dentro del rango, por eso vamos a aplicar el operador &lt;strong&gt;modulo&lt;/strong&gt; a la respuesta. Cualquier implementación que usemos, tenemos que saber que el resultado tiene que ser siempre el mismo ante la misma entrada, como una función pura y determinística.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;index1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dev.to/post-x"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
&lt;span class="n"&gt;index2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dev.to/post-x"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
&lt;span class="n"&gt;index3&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dev.to/post-x"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;

&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;De esta manera ya queda resuelto como podemos escribir un &lt;em&gt;bloom filter&lt;/em&gt;, para la lectura, básicamente es lo mismo, pero debemos preguntar si los indices son &lt;code&gt;true&lt;/code&gt; y ahi tenemos cómo podemos estudiar las respuestas que vimos previamente.&lt;/p&gt;

&lt;p&gt;Si &lt;strong&gt;algún indice nos da falso&lt;/strong&gt;, sabemos que la URL que enviamos no esta en nuestro filtro.&lt;/p&gt;

&lt;p&gt;Si &lt;strong&gt;todos los indices dan verdadero&lt;/strong&gt;, decimos que probablemente si, ya que, al tener un array "chico" y que las funciones hash tienen colisiones, puede que otra URL haya generado los mismos números o algo mas fácil, puede ser este ejemplo:&lt;br&gt;
La url 1 nos da el resultado 1, 3 y 6&lt;br&gt;
La url 2 nos da el resultado 2, 5 y 7&lt;br&gt;
la url 3 nos da el resultado 2, 3 y 7 -&amp;gt; nos da que sí son todos true, pero la url 3 en sí, no estaba guardada, por eso en el segundo check (puede ser una base de datos) nos da que no estaba.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;El &lt;em&gt;bloom filter&lt;/em&gt; es una buena opción para cuando queremos ahorrar tiempo y espacio. Puede usarse como alternativa de un hashmap o un cache, para hacer operaciones en memoria y evitarnos salidas de red. Espero que lo prueben en sus proyectos!&lt;/p&gt;

&lt;p&gt;Hasta la próxima!&lt;/p&gt;

&lt;p&gt;PS: &lt;a href="https://github.com/sponsors/tomiok"&gt;sponsoreame aca&lt;/a&gt; si te gusto el contenido &lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>go</category>
    </item>
    <item>
      <title>SSE con Golang y Nats</title>
      <dc:creator>Tomas Francisco Lingotti</dc:creator>
      <pubDate>Sun, 11 Sep 2022 16:12:42 +0000</pubDate>
      <link>https://forem.com/tomaslingotti/server-side-events-con-go-y-nats-casi-real-time-2bnm</link>
      <guid>https://forem.com/tomaslingotti/server-side-events-con-go-y-nats-casi-real-time-2bnm</guid>
      <description>&lt;p&gt;Arquitectura orientada a eventos con dos servicios comunicándose mediante Nats y enviando eventos con Golang.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qué es un &lt;em&gt;Evento&lt;/em&gt;?
&lt;/h2&gt;

&lt;p&gt;Para no ponernos muy técnicos innecesariamente, lo definimos como un suceso que queremos comunicarlo a otro servicio. Entonces es "algo" y vamos a enviarle esa información a alguien más.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entonces, qué es &lt;strong&gt;SSE&lt;/strong&gt;?
&lt;/h2&gt;

&lt;p&gt;Server side events es un protocolo que envía mensajes donde un servidor es la fuente (eventsource), que funciona perfecto para las aplicaciones que quieran mostrar datos de forma continua (streams). Además, la información que vamos a mostrar depende de los eventos que vayan ocurriendo, es decir que al momento de la ocurrencia, el cliente (con un poco de suerte) vamos a poder ver la información enviada desde el servidor sin tener que refrescar la pagina.&lt;/p&gt;

&lt;p&gt;Entonces vamos a conectarnos desde un browser a una URL y recibir mensajes sin necesidad de hacer nada más. Esto es conocido como XHR streaming, similar a las conocidas peticiones AJAX pero con un canal establecido y solo recibiendo eventos desde el servidor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tecnologías utilizadas
&lt;/h2&gt;

&lt;p&gt;Para esta demo, elegimos Golang, sin frameworks y &lt;a href="https://nats.io"&gt;nats&lt;/a&gt; que es, según ellos, un software de conectividad cloud native y nosotros lo vamos a usar como un pub-sub, alguien publica un mensaje y otro(s) se subscribe al tópico para tener ya disponibles los mensajes. Es por eso que siempre hablamos de &lt;em&gt;near real-time&lt;/em&gt; porque no podemos desprendernos de la latencia natural que existe en las comunicaciones, pero vemos que Go y Nats hacen muy bien su trabajo y con tan pocas lineas de código vamos a tener una ejecución rápida y eficiente.&lt;br&gt;
Docker lo vamos a usar para nuestra demo local.&lt;/p&gt;
&lt;h2&gt;
  
  
  Nuestro caso de uso
&lt;/h2&gt;

&lt;p&gt;Para el ejemplo, vamos a simular algunos drones están en un campo de batalla enemigo y escanean una zona en particular, obtienen información de las tropas, como cantidad de soldados, nivel de energía y experiencia (skill). Muchos drones en simultaneo van a estar enviando mensajes a través de nats, y el servicio de monitoreo los va a capturar, finalmente, vamos a ver los resultados en una web como streams de datos, cada vez que el monitor reciba un mensaje, lo procesa y lo envía por el canal de XHR streaming.&lt;br&gt;
Recordemos que streaming es una extension de XHR que nos permite tener datos (bytes) disponibles al mismo momento que llegan, independientemente de un buffer que se los contenga. &lt;/p&gt;

&lt;p&gt;Esta capacidad esta disponible en algunos browsers, no todos, por eso websockets sigue siendo muy popular pero de este modo tenemos conexión bidireccional, con el agregado HTTP que no tenemos usando websockets. Es por esto que vamos a tener que, mediante código, avisarle al cliente sí su navegador soporta nuestra operación.&lt;/p&gt;



&lt;p&gt;Ahora si nos vamos al editor&lt;/p&gt;

&lt;p&gt;En primer lugar vamos a definir el mensaje algunas estructuras y funciones.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Tanto Drone como Scan son para agrupar la info leída y las que componen la estructura de &lt;em&gt;Message&lt;/em&gt; la vamos a usar para enviar el JSON.&lt;/p&gt;

&lt;p&gt;Ahora para conectarnos a nats local y enviar mensajes, es muy fácil y casi imposible equivocarse. Va a correr sobre Docker.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Creo que no hace falta explicar mucho, lo unico importante de remarcar es el puntero a la conexion, ya que es una estructura y el subject que lo usamos como nombre del topico donde enviamos los mensajes.&lt;/p&gt;

&lt;p&gt;Para ejecutar localmente, el docker compose es mas facil aun.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;con un comando simple como &lt;code&gt;docker-compose up&lt;/code&gt; ya vamos a tener una instancia local.&lt;/p&gt;

&lt;p&gt;Con estas pocas lineas ya podemos enviar mensajes, ahora vamos a la otra sección, que es como vamos a recibirlos y mostrarlos.&lt;/p&gt;

&lt;h2&gt;
  
  
  servicio de monitoreo
&lt;/h2&gt;

&lt;p&gt;Ya los drones están enviando sus &lt;em&gt;scans&lt;/em&gt;, así que vamos a subscribirnos al tópico para leerlos.&lt;/p&gt;

&lt;p&gt;Para conectarnos usamos lo mismo.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;(ya vamos a usar el canal)&lt;/p&gt;

&lt;p&gt;Acá vemos como nats nos da una firma con una &lt;em&gt;closure&lt;/em&gt; para que hagamos el trabajo con el mensaje entrante. En nuestro caso se lo pasamos a otro canal (Nats también soporta nativamente la subscripción con canales en Go).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;El método &lt;code&gt;Listen()&lt;/code&gt; lo usamos de pasamanos y formateo, y el &lt;code&gt;ReadForever()&lt;/code&gt; para que sea capturar todos los mensajes. &lt;br&gt;
En main vamos a usar una goroutine separada para que readForever cumpla su trabajo.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Ahora pasamos a la última parte, enviar los streams al cliente web, en este caso un navegador.&lt;br&gt;
Vamos a usar la interfaz &lt;code&gt;Flusher()&lt;/code&gt; de Go que nos permite enviar los datos "en un buffer". Según la documentación, debemos validar en runtime si es posible hacer esta operación porque algunas implementaciones de los servidores web pueden no soportarlo.&lt;/p&gt;

&lt;p&gt;Dentro del bucle &lt;em&gt;infinito&lt;/em&gt; vamos a estar tomando todos los mensajes (podríamos usar la cláusula &lt;code&gt;range&lt;/code&gt; también) y dandole un formato mas legible. La otra linea importante es &lt;code&gt;Flush()&lt;/code&gt;para que &lt;em&gt;realmente&lt;/em&gt; el mensaje se termine de enviar.&lt;/p&gt;

&lt;p&gt;Por ultimo, no se olviden los headers, importante que el navegador conozca que no tiene que usar cache, mantener la conexión viva y que el content-type va a ser streaming.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Lo probamos
&lt;/h2&gt;

&lt;p&gt;Podemos usar cualquier navegador y al tener los dos servicios corriendo, ingresamos a &lt;code&gt;localhost:3335/listen&lt;/code&gt; (al menos asi lo tengo en mi GitHub y vamos a ver en tiempo real los eventos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Como vimos, el patrón SSE es muy interesante y con muchísimos casos de uso aplicables. Con pocas lineas de código, lo hacemos realidad y es a prueba de fallas. No entramos en comparación detallada con otras tecnologías como websockets porque la idea era mostrar una alternativa, aunque siempre se tienen que evaluar ambas.&lt;/p&gt;

&lt;p&gt;Espero que les haya gustado, los espero en comentarios y dejo todo el &lt;em&gt;source&lt;/em&gt;: &lt;a href="https://github.com/tomiok/nrt"&gt;https://github.com/tomiok/nrt&lt;/a&gt; y si te gustó, podes &lt;a href="https://github.com/sponsors/tomiok"&gt;sponsorearme aca&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>distributedsystems</category>
      <category>webdev</category>
      <category>eventdriven</category>
    </item>
  </channel>
</rss>
