<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[JLG FullStack Ninja]]></title><description><![CDATA[Solutions Architect && Full Stack Developer]]></description><link>https://jlgarcia.fulldev.ninja/</link><image><url>https://jlgarcia.fulldev.ninja/favicon.png</url><title>JLG FullStack Ninja</title><link>https://jlgarcia.fulldev.ninja/</link></image><generator>Jamify 1.0</generator><lastBuildDate>Mon, 08 Nov 2021 23:13:06 GMT</lastBuildDate><atom:link href="https://jlgarcia.fulldev.ninja/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Docker XIV - Kubernetes IX: Trabajando en Cloud]]></title><description><![CDATA[Bien hasta ahora hemos estado haciendo todo en nuestro entorno local de pruebas,
veamos como podemos trabajar con un entorno en cloud desde nuestro terminal con
kubectl
Kubectl es una herramienta de linea de comandos para trabajar con cualquier tipo
de cluster de kubernetes, en nuestro caso nos hemos creado un minientorno de
pruebas usando minikube. Al hacer la instalación de minikube y kubectl
automáticamente se configura para que estemos usando ese entorno por defecto (el
de minikube) pero no]]></description><link>https://jlgarcia.fulldev.ninja/docker-xiii-kubernetes-viii-pensando-en-un-entorno-con-microservicios-usando-ingress-2/</link><guid isPermaLink="false">Ghost__Post__600ac23ff73ef66cb4cf74dc</guid><category><![CDATA[Docker]]></category><category><![CDATA[kubernetes]]></category><category><![CDATA[cloud]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 15 Feb 2021 09:30:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/a8e77ba5b1852585391f8ffab9564f47/learning-docker-and-k8s-by-practice-5.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://jlgarcia.fulldev.ninja/static/a8e77ba5b1852585391f8ffab9564f47/learning-docker-and-k8s-by-practice-5.jpg" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud"/><p>Bien hasta ahora hemos estado haciendo todo en nuestro entorno local de pruebas, veamos como podemos trabajar con un entorno en cloud desde nuestro terminal con kubectl</p><p>Kubectl es una herramienta de linea de comandos para trabajar con cualquier tipo de cluster de kubernetes, en nuestro caso nos hemos creado un minientorno de pruebas usando <em>minikube.</em> Al hacer la instalación de minikube y kubectl automáticamente se configura para que estemos usando ese entorno por defecto (el de minikube) pero nosotros podemos cambiarlo en cualquier comento.</p><p>Para ver la configuración que tenemos actualmente podemos ejecutar el comando</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl config view</code></pre></div><p>Esto nos debe mostrar algo similar a</p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image.png 723w" sizes="(min-width: 720px) 720px"/></figure><p>En esta configuración tenemos 4 cosas importantes:</p><ul><li><strong>clusters</strong>: Información de todos los cluster que tenemos configurados, con su certificado, su dirección o hostname y el propio nombre que le hemos dado al cluster en cuestión</li><li><strong>contexts</strong>: Todos los contextos que tenemos configurados. Esto puede parecer redundante, pero no es así, realmente nosotros trabajamos a través de los contextos y estos apuntan a un cluster en específico. Esto es así porque podemos tener distintos usuarios de acceso según el contexto y podemos querer configurar un <em>namespace</em> diferente del de por defecto (namespace es solo una separación lógica de objetos dentro de kubernetes)</li><li><strong>current-context</strong>: El contexto seleccionado actualmente</li><li><strong>users</strong>: Usuarios con sus nombres y sus métodos de acceso.</li></ul><p>Estos serían los puntos relevantes que tenemos que tener en cuenta a la hora de intentar conectarnos a otro cluster. </p><p>Como tal <em>kubectl nos provee de los comandos necesarios para cambiar el contexto, ver el contexto actual, configurar nuevo cluster, cualquier cosa que necesitemos realmente. Por ejemplo:</em></p><figure class="kg-card kg-code-card"><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl config current-context</code></pre></div><figcaption>Para ver el contexto actual</figcaption></figure><p>Estos serían todos los comandos bajo <strong>config</strong></p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-1.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-1.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-1.png 773w" sizes="(min-width: 720px) 720px"/></figure><p>Visto más o menos que nos ofrece kubectl para seleccionar una configuración u otra veamos como hacer despliegue de kubernetes en Google</p><h2 id="hacia-google-cloud">Hacia Google Cloud</h2><p>Google cloud es el servicio cloud que mejor funciona con kubernetes (nació allí por lo que tiene sentido no?). En este sentido es el servicio con el que más rápido podremos configurar nuestro cluster de kubernetes, vamos a por ello:</p><p>Primero sería darnos de alta en google cloud, si no tenéis cuenta sería el momento de hacerlo. Una vez que tengamos nuestra cuenta lo que debemos hacer es instalar la linea de comandos de google (gcloud). Buscar en internet como realizar esta instalación en el caso de que no uséis <em>brew</em> para instalar paquetes, si lo tenéis solo es necesario hacer </p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">brew <span class="token function">install</span> google-cloud-sdk</code></pre></div><p>Para empezar, lo primero que tenemos que hacer una vez instalado es iniciar la configuración de nuestro servicio:</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">gcloud init</code></pre></div><p>Con este estableceremos una configuración nueva o seleccionaremos una existente si ya la tenemos, aquí cada uno puede configurar lo que quiera y como quiera. Como tal yo tengo un proyecto creado que es: <strong>kuber-project-example</strong></p><p>Si en algún caso os falla cualquier comando, puede ser por la versión que ha instalada brew del SDK, seguir estos pasos:</p><ul><li>Cambiar versión de python de la console</li></ul><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">export</span> <span class="token assign-left variable">CLOUDSDK_PYTHON</span><span class="token operator">=</span>python2</code></pre></div><ul><li>Actualizar los componentes</li></ul><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">gcloud components update</code></pre></div><p>Con esto ya os funcionaria todo (o debería). Continuemos:</p><p>Ahora lo que haremos será seleccionar ese proyecto como base para el resto de comandos</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">gcloud config <span class="token builtin class-name">set</span> project kuber-project-example</code></pre></div><p>Y también es necesaria tener una región de computo configurada</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">gcloud config <span class="token builtin class-name">set</span> compute/zone us-west1-a</code></pre></div><p>En este punto puede que os pida seleccionar una cuenta de facturación (por si te vuelves loco creando cosas jajajajaja). Esto lo más fácil es irse a la consola de google, irse al menú de facturación y seleccionar una de las cuentas (o crearla)</p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-2.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-2.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-2.png 765w" sizes="(min-width: 720px) 720px"/></figure><p>Una vez seleccionada una cuenta en la consola de google, volvemos a ejecutar el comando, nos pedirá habilitar la API de "compute.googleapis.com", la habilitamos(tardará un poco) y ya nos confirmará que la configuración se ha actualizado o añadido</p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-3.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-3.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-3.png 926w" sizes="(min-width: 720px) 720px"/></figure><p>A continuación creamos nuestro cluster de kubernetes que también puede que nos de error porque necesitamos habilitar el servicio de contenedores en nuestro proyecto</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">gcloud container clusters create ninja-cluster --num-nodes<span class="token operator">=</span><span class="token number">1</span></code></pre></div><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-4.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-4.png 600w, https://jlgarcia.fulldev.ninja/assets/images/size/w1000/2021/01/image-4.png 1000w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-4.png 1158w" sizes="(min-width: 720px) 720px"/></figure><p>Por lo que si nos aparece este error habilitaremos ese servicio también</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">gcloud services <span class="token builtin class-name">enable</span> container.googleapis.com</code></pre></div><p>Y ya si todo va bien y no nos pide nada más ejecutamos de nuevo </p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">gcloud container clusters create ninja-cluster --num-nodes<span class="token operator">=</span><span class="token number">1</span></code></pre></div><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-5.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-5.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-5.png 811w" sizes="(min-width: 720px) 720px"/></figure><p>Y ya cuando termine el proceso nos confirmará los datos pertinentes según lo que hayamos solicitado</p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-6.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-6.png 600w, https://jlgarcia.fulldev.ninja/assets/images/size/w1000/2021/01/image-6.png 1000w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-6.png 1015w" sizes="(min-width: 720px) 720px"/></figure><p>Ahora lo siguiente es configurar nuestro kubectl local para que apunte a este cluster.... que lo podíamos hacer a mano, pero en esta caso google nos provee de un comando mágico que nos añade la configuración a la kube config</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">gcloud container clusters get-credentials ninja-cluster</code></pre></div><p>Básicamente es solicitarle las credenciales sobre un cluster en específico y listo</p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-7.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud"/></figure><p>Veamos la config</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl config view</code></pre></div><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-8.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-8.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-8.png 627w"/></figure><p>Como vemos ahora tenemos otro cluster, otro contexto y otro usuario y si nos fijamos en nuestro <strong>current-context </strong>ya no estamos en minikube si no en el de google</p><p>Veamos que tenemos ahora con nuestro comando para ver los nodos</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl get nodes</code></pre></div><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-9.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-9.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-9.png 829w" sizes="(min-width: 720px) 720px"/></figure><p>Ahora tenemos nuestro nodo de cluster de kubernetes que le hemos indicado que cree. Probemos ahora a crear un deploy, usaremos el de ejemplo de kubernetes que es una imagen básica de google</p><div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create deployment web --image<span class="token operator">=</span>gcr.io/google-samples/hello-app:1.0</code></pre></div><p>Y comprobemos que nos ha creado</p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-10.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud"/></figure><p>Como tal podemos ejecutar en este caso todos los comandos que hemos ido viendo hasta ahora. Añadamos un service para poder acceder a nuestro deploy, en este caso vamos a añadir un <strong>service de tipo LoadBalancer</strong> (por fin jejejejje) que esto lo que hará será que google cloud nos creará un balanceador de carga y accederemos a nuestro pod desde él.</p><p>Una vez que tengamos ip externa</p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-11.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-11.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-11.png 700w"/></figure><p>Ya deberíamos poder acceder a nuestro pod, ojo en este caso tenemos que acceder por IP y al puerto 8080 (si habéis usado mi ejemplo porque el puerto del comando ha sido el 8080)</p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/image-12.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/image-12.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/image-12.png 606w"/></figure><p>En este caso podemos comprobar como de facil es trabajar con kubernetes en google cloud y la configuración no es complicada. Si queremos ver que realmente no es mentira podemos irnos a la consola de kubernetes y ver que es lo que tenemos creado</p><figure class="kg-card kg-image-card"><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-14.49.33.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/Captura-de-pantalla-2021-01-22-a-las-14.49.33.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-14.49.33.png 684w"/></figure><p>Y ya para aseguraros de que no miento podemos ver que nos ha creado también un balanceador de carga apuntando a nuestro cluster</p><figure class="kg-card kg-image-card kg-card-hascaption"><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-14.54.25.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/Captura-de-pantalla-2021-01-22-a-las-14.54.25.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-14.54.25.png 993w" sizes="(min-width: 720px) 720px"><figcaption>Lista de balanceadores de carga</figcaption></img></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-14.54.36.png" class="kg-image" alt="Docker XIV - Kubernetes IX: Trabajando en Cloud" srcset="https://jlgarcia.fulldev.ninja/assets/images/size/w600/2021/01/Captura-de-pantalla-2021-01-22-a-las-14.54.36.png 600w, https://jlgarcia.fulldev.ninja/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-14.54.36.png 778w" sizes="(min-width: 720px) 720px"><figcaption>Detalles del balanceador de carga</figcaption></img></figure><p>Creo que queda más o menos claro como trabajar con la cloud de google y kubernetes, que es realmente sencillo. Con esto ya podríamos crear infraestructuras tan complejas como quisiéramos que con unos cuantos comandos ya se encarga google de hacerte la magia.</p><p>Y hasta aquí la parte de google cloud<strong> (NO SE OS OLVIDE BORRAR LAS COSAS DE GOOGLEEEEEE CLOUUUUD JEJEJJEJEJE)</strong></p><h2 id="aws">AWS</h2><p>Para hacerlo en aws...... pues realmente es más fácil que lo veáis directamente de la documentación porque es realmente igual de trivial, lo único que nos ofrece 2 opciones:</p><ol><li><strong>Usar eksctl: </strong>Es una herramienta de línea de comandos específica de <strong>Amazon EKS </strong>(servicio de kubernetes de AWS) que es bastante fácil de usar y a su vez nos da la opción de crear nuestro cluster con <strong>Fargate</strong> o no. <a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html">Ver esta opción</a></li><li><strong>Usar el CLI de AWS y la consola de administración: </strong>Aquí se hace uso de <strong>CloudFormation</strong> otro servicio interesante de AWS que nos facilita la orquestación de algunas cosas, esta opción es algo más manual porque es necesario manejar algunos permisos de IAM y cosas así pero se ve algo más de que es lo que estamos montando. <a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html">Ver esta opción</a></li></ol><p>Ambas opciones realmente son sencillas y para probar son más que suficientes, recomiendo que intentar cualquiera de ellas y ver que es realmente lo que se monta en la consola de AWS <strong>(BORRARLOOOOOO que al final cobran por tener el espacio en uso indefinidamente tras el año gratuito)</strong></p><p>Bueno y hasta aquí lo que veremos de Docker y Kubernetes por el momento, han sido un montón de posts al respecto espero que os hayan parecido interesantes, se que nos faltaría ver como ser haría con Azure pero realmente es una plataforma que no me gusta mucho (es personal ojo no digo que sea mala ni nada por el estilo) por lo que no lo veremos aquí ni lo comentare, seguro que existe muy buena documentación al respecto para quien esté interesado.</p><p>Clausuro esta serie de posts pero no descarto en ningún momento plantear más cosas sobre kubernetes y docker en un futuro cercano, sin mucho más que deciros NOS VEMOS EN EL SIGUIENTEEEEEEE un abraazoooooooo</p>]]></content:encoded></item><item><title><![CDATA[Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS]]></title><description><![CDATA[Hasta ahora hemos planteado nuestro entorno pensando solo en una o varías
aplicaciones que realmente funcionan de manera autonóma, es decir, si pensamos
en nuestro POD con el fork del juego de SUPER MARIO vemos como realmente no
tiene comunicación con nada más y en un primer momento no la necesita (o
nosotros a la hora de usarlo tampoco).
Ahora propongo otro escenario, como pudiera ser que tenemos un pequeño portal
donde el usuario necesita hacer login antes de poder acceder a nuestro juego. Si]]></description><link>https://jlgarcia.fulldev.ninja/docker-xiii-kubernetes-viii-pensando-en-un-entorno-con-microservicios-usando-ingress/</link><guid isPermaLink="false">Ghost__Post__6004188da6c0f5058bff4dbd</guid><category><![CDATA[Docker]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 08 Feb 2021 09:37:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/a8e77ba5b1852585391f8ffab9564f47/learning-docker-and-k8s-by-practice-4.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/a8e77ba5b1852585391f8ffab9564f47/learning-docker-and-k8s-by-practice-4.jpg" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/><p>Hasta ahora hemos planteado nuestro entorno pensando solo en una o varías aplicaciones que realmente funcionan de manera autonóma, es decir, si pensamos en nuestro POD con el fork del juego de SUPER MARIO vemos como realmente no tiene comunicación con nada más y en un primer momento no la necesita (o nosotros a la hora de usarlo tampoco).</p>
<p>Ahora propongo otro escenario, como pudiera ser que tenemos un pequeño portal donde el usuario necesita hacer login antes de poder acceder a nuestro juego. Si lo planteamos como si realmente fueran servicios distintos tendriamos por ejemplo:</p>
<ul>
<li>Lo que es el front, que no sería más que una miniweb con un login y a lo mejor una lista de posibles juegos.</li>
<li>Puede que un microservicio que gestionaría los usuarios y nos permitiría hacer login o un microservicio que fuera realmente la API con la lista de juegos disponibles</li>
<li>Y por dejarlo simple un microservicio que sería el fork de nuestro juego de SUPER MARIO y otro que puede ser un fork del SONIC por ejemplo.</li>
</ul>
<p>Es posible que este escenario no tenga ningún sentido ojo, por el tema de la autenticación y demás, es solo para que entendamos que tendríamos varios microservicios distintos que gestionar. Esto con los objetos y configuraciones que hemos visto hasta ahora puede que lo pudieramos conseguir si tenemos un objeto de tipo <em>SERVICE:NODEPORT</em> por cada microservicio y el microservicio de front sepa donde esta todo (superfeo) o a lo mejor hacerlo con subdominios y con DNS o cosas así (se me están ocurriendo sobre la marcha pueden no tener sentido). El caso es que a no ser que lo gestionaramos en un servicio cloud que nos pudiera hacer el enrutamiento no tenemos una forma clara de hacerlo. Bueno pues para esto tenemos en kubernetes el objeto de tipo <strong>INGRESS</strong>.</p>
<p>Este objeto lo que hace es definir como se deben gestionar las peticiones que vienen desde fuera de nuestro cluster, es decir, hacia donde debe redireccionar cada petición. Veamos una diagrama de la documentación oficial donde creo yo que se explica bastante bien cual es la tarea de nuestro INGRESS</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-17-a-las-18.58.18.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Este diagrama que vemos resume un escenario típico que tendríamos en producción:</p>
<ol>
<li>El cliente envía una petición que lo primero que hace es llegar al balanceador de carga de nuestro cloud. Este balanceador de carga está manejado por un <strong>INGRESS CONTROLLER</strong> que es el que se encarga de asegurarse de que se cumplan las reglas que definimos en nuestro objeto <em>INGRESS</em></li>
<li>Según las reglas que hayamos definido nuestro INGRESS CONTROLLER decide a que servicio (objeto de tipo <em>SERVICE</em>) de nuestro cluster debe enviar la petición en cuestión</li>
<li>Por último este <em>service</em> envía la petición al primero de sus PODS que este disponible</li>
</ol>
<p>Un detalle que no hemos dejado claro todavía es que <strong>las reglas que definimos en el objeto de tipo <em>INGRESS</em> no son manejadas realmente por kubernetes, si no que necesitamos de un controlador externo (<em>INGRESS CONTROLLER</em> para que las gestione)</strong>. Como tal existen opciones de configuración de <em>ingress</em> disponibles para NGINX, HAPROXY, TRAEFIK... para la mayoría de los servicios de proxy, uno de los más típicos es el de nginx. En un entorno en cloud seria necesario tener un POD con nginx que sería nuestro INGRESS CONTROLLER.</p>
<p>Comentar que el entorno completo en cloud con su loadbalancer, su ingress y demás no lo veremos de momento, en la <a href="https://kubernetes.io/docs/concepts/services-networking/ingress/">documentación oficial</a> viene todo lo necesario creo yo, por ahora con motivos puramente de prueba o académicos usaremos la opción que nos provee <em>minikube</em> para tener nuestro propio INGRESS CONTROLLER.</p>
<p>Veamos lo primero un ejemplo de objeto tipo <em>INGRESS</em>, como no parece existir de momento comando <em>dry-run</em> para verlo, nos tocará copiar un ejemplo como este</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mario-ingress
spec:
rules:
- host: mariogame.fulldev.ninja
http:
paths:
- path: /mario
pathType: Prefix
backend:
service:
name: mario-service
port:
number: 8000
defaultBackend:
service:
name: default-service
port:
number: 8001
</code></pre></div>
<p>Creo que es bastante intuitivo lo que hace cada cosa pero hablemos un poco en detalle de algunos puntos:</p>
<ul>
<li><strong>apiVersion: networking.k8s.io/v1</strong>: Aquí si nos fijamos tenemos un cambio respecto a lo que soliamos indicar en el resto de objetos, en este caso debemos especificar que pertenece a la api de networking de kubernetes.</li>
<li><strong>spec</strong>: Como siempre dentro de spec tenemos siempre la definición de lo que queremos hacer.</li>
<li><strong>rules</strong>: Dentro de rules como su propio nombre indica es donde definiremos las reglas que queremos usar dentro de nuestro ingress
<ul>
<li><strong>host</strong>: hostname al cual enviará el cliente las peticiones</li>
<li><strong>http -> paths</strong>: Estos serán los paths que usará nuestro ingress controller para redireccionar la petición a un servicio o a otro.</li>
<li><strong>pathType</strong>: Como se filtrarán los paths, el caso más típico es el de <em>Prefix</em> que buscará coincidencias en el path completo separandolo por /</li>
<li><strong>backend -> service</strong>: El servicio que debe responder al path indicado</li>
</ul>
</li>
<li><strong>defaultBackend</strong>: Aquí definimos el servicio por defecto en caso de que no se encontraran coincidencias en el resto de reglas</li>
</ul>
<p>Como siempre existen muchas más reglas pero estas son las básicas y que me han parecido relevantes para empezar (vuelvo a recomendar leer la documentación oficial)</p>
<p>Una vez visto lo básico, veamos como configurar un <em>ingress controller</em> en minikube (recordemos que en un entorno cloud tenemos que tener nuestro propio pod que haga de controller).<br>
Para ello lo primero es hablar de los <strong>addons</strong> de minikube. Minikube dispone de ciertos <em>extras</em> que podemos habilitar según nos insterese, uno de ellos es el <em>ingress controller</em>, este ingress que nos provee minikube es una propia intancia de nginx preparada para este uso y que en este caso no podremos ver como uno de los pods que hemos estado viendo hasta ahora (en un momento veremos lo que pasa)</br></p>
<p><strong>OJO esta parte solo funciona si has iniciado minikube con algún gestor de máquinas virtuales como virtualbox <a href="https://minikube.sigs.k8s.io/docs/reference/drivers/virtualbox/">doc oficial</a>. Ver al final del post el apartodo INICIAR MINIKUBE CON VIRTUALBOX o también es posible jugar con <a href="https://labs.play-with-k8s.com/">este playground</a></strong></p>
<p>Primero veamos la lista de addons, para ello solo es necesario que ejecutemos este comando:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">minikube addons list
</code></pre></div>
<p>Esto nos mostrará una lista de los addons disponibles indicándonos si están habilitados o no (algunos estarán habilitados por defecto según nuestra instalación)</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-10.42.44.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Si os fijáis uno de los addons que aparecen es el de <em>ingress</em>, habilitemoslo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">minikube addons <span class="token builtin class-name">enable</span> ingress
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-11.08.49.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Con esto ya tendríamos habilitado nuestro ingress controller con nginx, pero como he comentado no nos aparece como un pod normal en este entorno.</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-11.10.12.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Minikube en este caso lo crea como un pod propio del sistema de minikube por lo que para verlo tendríamos que listar los pods que pertenecen a minikube, para ello</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl get pods -n kube-system
</code></pre></div>
<p>Y esto nos listará todos los pods que va creando minikube</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-11.12.23.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Si nos fijamos tenemos uno en específico que se llama <em>nginx-controller</em>.</p>
<p>Bien con esto ya tendríamos nuestro ingress controller, ahora vamos a trabajar con los mismos ejemplos que la documentación oficial (el de mario da algunos problemas con los direccionamientos y por no entrenernos), primero el deploy</p>
<p><strong>example-deploy.yaml</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> apps/v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Deployment
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> web
<span class="token key atrule">name</span><span class="token punctuation">:</span> web
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">2</span>
<span class="token key atrule">selector</span><span class="token punctuation">:</span>
<span class="token key atrule">matchLabels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> web
<span class="token key atrule">strategy</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token key atrule">template</span><span class="token punctuation">:</span>
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> web
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">containers</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> gcr.io/google<span class="token punctuation">-</span>samples/hello<span class="token punctuation">-</span>app<span class="token punctuation">:</span><span class="token number">1.0</span>
<span class="token key atrule">name</span><span class="token punctuation">:</span> hello<span class="token punctuation">-</span>app
<span class="token key atrule">resources</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token key atrule">status</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>El service</p>
<p><strong>mario-service.yaml</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Service
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> web
<span class="token key atrule">name</span><span class="token punctuation">:</span> web
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">protocol</span><span class="token punctuation">:</span> TCP
<span class="token key atrule">targetPort</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">selector</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> web
<span class="token key atrule">type</span><span class="token punctuation">:</span> NodePort
<span class="token key atrule">status</span><span class="token punctuation">:</span>
<span class="token key atrule">loadBalancer</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Hacemos los create pertinentes que ya hemos visto anteriormente</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create -f example-deploy.yaml
kubectl create -f example-service.yaml
</code></pre></div>
<p>Y por último preparamos nuestro ingress</p>
<p><strong>example-ingress.yaml</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> networking.k8s.io/v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Ingress
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">name</span><span class="token punctuation">:</span> example<span class="token punctuation">-</span>ingress
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">rules</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">host</span><span class="token punctuation">:</span> hello<span class="token punctuation">-</span>world.info
<span class="token key atrule">http</span><span class="token punctuation">:</span>
<span class="token key atrule">paths</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">path</span><span class="token punctuation">:</span> /
<span class="token key atrule">pathType</span><span class="token punctuation">:</span> Prefix
<span class="token key atrule">backend</span><span class="token punctuation">:</span>
<span class="token key atrule">service</span><span class="token punctuation">:</span>
<span class="token key atrule">name</span><span class="token punctuation">:</span> web
<span class="token key atrule">port</span><span class="token punctuation">:</span>
<span class="token key atrule">number</span><span class="token punctuation">:</span> <span class="token number">8080</span>
</code></pre></div>
<p>Y creamos nuestro ingress</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create -f example-ingress.yaml
</code></pre></div>
<p>Esto nos creará nuestro ingress tardará un poco en tenerlo todo (fijaos en el ADDRESS)</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-12.26.20.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Como véis tenemos nuestro ingress creado, un detalle para que no nos alarmemos es el warning que aparece. Nosotros en nuestra definición de ingress hemos definido el uso de la api de kubernetes v1, lo que pasa es que el comando <em>get ingress</em> comprueba la existencia de ingress desde la primera versión que tiene disponible, por eso el aviso, no quiere decir que nuestra definición de ingress esté realmente mal.</p>
<p>Bien ahora que ya tenemos nuestro ingress desplegado veamos como podemos acceder a el. La primera intención puede ser intentar acceder por la IP, pero si lo intentamos veremos un 404 de nginx. Esto no es del todo malo, comprobamos que tenemos comunicación con nuestro ingress controller</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-11.35.58.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Para el que no sepa realmente como funcionan los proxys como nginx, lo que hacen normalmente es esperar que el acceso se produzca con un nombre de host específico, es posible que tengamos varios hostname distintos bajo el mismo nginx. En nuestro mismo caso podemos querer tener otro hostname para otro servicio que <strong>bye-world.info</strong></p>
<p>Entonces lo que tenemos que hacer es modificar nuestra definición local de redirecciones IP/HOSTNAME, en mi caso lo tengo que hacer en el fichero <strong>/etc/hosts</strong></p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-12.26.20-1.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Una vez modificado si accedemos al hostname en cuestión veremos como accedemos sin problema al servicio pertinente</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-12.28.09.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Con esto tendríamos funcionando un ingress controller que puede redireccionar multiples peticiones a distintos servicios basandonse en el nombre del hosts o un path (en nuestro hemos puesto <strong>/</strong> pero podría ser cualquier otro)</p>
<p>Con esto habríamos visto lo básico para trabajar con ingress, el resto ya es revisar la documentación y ver las distintas opciones que nos ofrece kubernetes para cumplir con nuestras necesidades, sin mucho más terminamos este post, nos vemos en el siguiente un abrazooooorrrr</p>
<h3 id="iniciarminikubeconvirtualbox">INICIAR MINIKUBE CON VIRTUALBOX</h3>
<p>Esta es una sección para los que hayan estado jugando con el propio driver de docker (el que nos provee docker-desktop) para probar kubernetes que al final llega un punto en el que algunas cosas no funcionan de ninguna forma (depende de las versiones, van incluyendo poco a poco funcionalidades compatibles).</p>
<p>Lo primero que tenemos que hacer es borrar minikube de nuestro entorno, recomiendo borrar todo y hacer una instalación limpia para ello lo primero es:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">minikube delete --all --purge
</code></pre></div>
<p>Esto nos borra todo lo que tenemos de minikube</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-11.02.33.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>A continuación instalamos virtualbox -> <a href="https://www.virtualbox.org/wiki/Downloads">Downlaads</a></p>
<p>Una vez instalado todo lo que hacemos es arrancar minikube con el driver de virtualbox</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">minikube start --driver<span class="token operator">=</span>virtualbox
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-11.03.47.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Esto tardara un rato hasta crea las máquinas virtuales pertinentes</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-22-a-las-11.06.40.png" alt="Docker XIII - Kubernetes VIII: Pensando en un entorno con microservicios usando INGRESS"/></p>
<p>Con esto ya tendriamos arrancado nuestro minikube con un cluster de maquines virtuales. Well done!!!</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker XII - Kubernetes VII: Escalando PODS]]></title><description><![CDATA[Hasta ahora en los post anteriores hemos estado trabajando con solo un POD o una
instancia de cada POD. Pero para realmente tener ese escenario no necesitamos
kubernetes podiamos hacerlo igual con docker o con docker-conpose. Veamos ahora
realmente algo de lo que nos ofrece realmente kubernetes que es la posibilidad
de gestionar multiples instancias de un mismo POD.
Esto lo hace kubernetes posible haciendo uso de los objetos con tipo Deployment,
es un objeto muy similar al POD con el que hemos]]></description><link>https://jlgarcia.fulldev.ninja/docker-xii-kubernetes-vii-multiplicando-pods/</link><guid isPermaLink="false">Ghost__Post__6003341fa6c0f5058bff4d9e</guid><category><![CDATA[Docker]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 01 Feb 2021 09:39:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-3.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-3.jpg" alt="Docker XII - Kubernetes VII: Escalando PODS"/><p>Hasta ahora en los post anteriores hemos estado trabajando con solo un POD o una instancia de cada POD. Pero para realmente tener ese escenario no necesitamos <em>kubernetes</em> podiamos hacerlo igual con <em>docker</em> o con <em>docker-conpose</em>. Veamos ahora realmente algo de lo que nos ofrece realmente kubernetes que es la posibilidad de gestionar multiples instancias de un mismo POD.</p>
<p>Esto lo hace kubernetes posible haciendo uso de los objetos con tipo <em>Deployment</em>, es un objeto muy similar al POD con el que hemos estado trabajando solo que nos permite indicarle cuantas instancias queremos de un mismo pod. Para ver un ejemplo podemos hacer, como siempre, uso de un comando <em>dry-run</em>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create deployment mario-deploy --image<span class="token operator">=</span>pengbai/docker-supermario:latest --port<span class="token operator">=</span><span class="token number">8080</span> --dry-run<span class="token operator">=</span>client -o yaml <span class="token operator">></span> mario-deployment.yaml
</code></pre></div>
<p>Esto nos creará un documento similar a este:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> apps/v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Deployment
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>deploy
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>deploy
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">1</span>
<span class="token key atrule">selector</span><span class="token punctuation">:</span>
<span class="token key atrule">matchLabels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>deploy
<span class="token key atrule">strategy</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token key atrule">template</span><span class="token punctuation">:</span>
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>deploy
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">containers</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> pengbai/docker<span class="token punctuation">-</span>supermario<span class="token punctuation">:</span>latest
<span class="token key atrule">name</span><span class="token punctuation">:</span> docker<span class="token punctuation">-</span>supermario
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">resources</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token key atrule">status</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Veamos un poco que es lo que tenemos aquí:</p>
<ul>
<li><strong>metadata</strong>: Ya hemos visto en el resto de posts que es esto. Contiene <em>labels</em> identificativos que nos pueden ser utiles para hacer referencia desde otros objetos del cluster de kubernetes. Y también tiene su <em>name</em> para identificar este objeto como tal.</li>
</ul>
<p>Dentro del <strong>spec</strong>, que recordemos que es donde realmente se define la <em>magia</em> tenemos nuevo:</p>
<ul>
<li><strong>replicas</strong>: Creo que es autoexplicativo. Podemos indicar la cantidad de instancias que queremos de un tipo de POD.</li>
<li><strong>selector</strong>: Al igual que pasaba con el objeto de tipo <em>service</em>, dentro de este selector indicamos los labels que tienen los pods que debe gestionar este objeto de tipo deployment.</li>
<li><strong>template</strong>: Aquí es donde definimos el POD en cuestión que tiene que usar como plantilla, es decir, usando un objeto de tipo deployment ya no es necesario tener por otro lado un objeto de tipo POD, puede estar definido dentro de esta template (si los comparamos la definión debe ser muy similar)</li>
</ul>
<p>Una vez repasadas más o menos las diferencias veamos que pasa, <strong>cambiemos la cantidad de replicas a 2</strong> y ejecutemos el típico create</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-20.05.28.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Si comprobamos los pods que tenemos ahora veremos algo distinto</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-20.07.34.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Vemos como ahora ahora los pods se crean de otra manera, contienen el nombre del objeto deploy y además una conjunto alfanumerico, eso convierte el nombre del pod un identificador único. Además de comprobar los pods, ahora podemos usar otro comando específico para deployments</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl get deployments
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-20.10.29.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Que como podemos comprar nos muestra cuando pods tiene el deployment, cuandos estan activos y cuantos estan actualizados con la última versión (ya hablaremos de esto). Si ahora nosotros eliminamos uno de los pods, veremos como automáticamente nos crea uno nuevo.</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-20.12.43.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Kubernetes, como siempre, en su ciclo de vida (llamada bucle de reconciliación) comprueba que el estado de los objetos que están en funcionamiento cumple con sus definiones/plantillas y si no, pues actua en consecuencia, en este caso con la creación de un nuevo POD usando la plantilla que tiene el objeto de tipo <em>deployment</em>.</p>
<p>Pero claro ahora mismo hemos definido de antemano el número de replicas que queremos de un mismo POD dentro de la plantilla de deploy, pero... ¿y si tengo que <em>escalar</em> mi aplicación ahora mismo entando en producción? pues para ello tenemos varias opciones:</p>
<ul>
<li>Editar el estado actual de nuestro deploy en la API</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl edit deploy mario-deploy
</code></pre></div>
<p>Nos aparecerá la definición que está actualmente en la API de kubernetes, lo que podemos hacer es editar el número de réplicas y esto nos debería escalar el número de instancias de pods</p>
<ul>
<li>Otra forma es usando el comando <em>scale</em></li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl scale deployment mario-deploy --replicas<span class="token operator">=</span><span class="token number">3</span>
</code></pre></div>
<p>En cualquiera de los 2 casos si comprobamos los pods que tenemos deberían haber aumentado</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-20.28.51.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Y lo mismo podemos hacer para reducirlos, si disminuimos el número de replicas nos eliminará el número de instancias activas</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl scale deployment mario-deploy --replicas<span class="token operator">=</span><span class="token number">1</span>
</code></pre></div>
<p>Comprobamos que empieza con la eliminación de 2 de las instancias y al final nos deja solo con una</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-20.30.59.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<h3 id="actualizandoversionesdenuestraaplicacinyrollback">Actualizando versiones de nuestra aplicación y rollback</h3>
<p>Todo lo que hemos visto en este post está muy bien, pero normalmente ninguna aplicación se mantiene en la misma versión para siempre, como tal, es necesario actualizarla en algún momento, en esta sección veremos como cambiar la versión de nuestra imagen y también como hacer rollback en caso de que algo falle. Todo esto es realmente sencillo gracias a kubernetes.</p>
<p>Primero de todo vamos a seleccionar una imagen que tenga varias versiones, para no complicarnos creando nosotros un contenedor específico me he decantado por usar la imagen oficial de <a href="https://hub.docker.com/_/nginx">NGINX</a>, como se puede ver entre los tags de versiones tenemos dos que son fáciles de diferencias <em>stable</em> y <em>latest</em></p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-21.06.18.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Primero creemos nuestro deployment con la imagen stable, para ello crearemos un fichero yaml con estos datos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> apps/v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Deployment
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>deploy
<span class="token key atrule">name</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>deploy
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">2</span>
<span class="token key atrule">selector</span><span class="token punctuation">:</span>
<span class="token key atrule">matchLabels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>deploy
<span class="token key atrule">strategy</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token key atrule">template</span><span class="token punctuation">:</span>
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>deploy
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">containers</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> nginx<span class="token punctuation">:</span>stable
<span class="token key atrule">name</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>pod
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">80</span>
<span class="token key atrule">resources</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token key atrule">status</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Como véis tenemos 2 replicas de la versión <strong>nginx:stable</strong>, ejecutemos el comando crear y comprobemos que pasa (recomiendo eliminar todo lo que hicimos anteriormente, recordar con <em>kubectl delete ....</em>)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create -f nginx-deploy.yaml
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-21.10.17.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Ya tenemos nuestros 2 pods que hemos definido en el deploy, ahora comprobemos la versión con la que se han creado con el comando describe</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl describe deploy nginx-deploy
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-21.11.36.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Si nos fijamos tenemos dentro de <em>containers</em> la imagen seleccionada que es <em>nginx:stable</em>, ahora veamos las opciones para actualizar de versión</p>
<ol>
<li><strong>Usar el comando apply</strong><br>
Tenemos la posibilidad de actualizar la configuración actual de un objeto en kubernetes usando el comando <em>apply</em>, modificando nuestro fichero de deploy. Cambiemos la versión en nuestro fichero</br></li>
</ol>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> apps/v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Deployment
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>deploy
<span class="token key atrule">name</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>deploy
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">2</span>
<span class="token key atrule">selector</span><span class="token punctuation">:</span>
<span class="token key atrule">matchLabels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>deploy
<span class="token key atrule">strategy</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token key atrule">template</span><span class="token punctuation">:</span>
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>deploy
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">containers</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> nginx<span class="token punctuation">:</span>latest
<span class="token key atrule">name</span><span class="token punctuation">:</span> nginx<span class="token punctuation">-</span>pod
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">80</span>
<span class="token key atrule">resources</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token key atrule">status</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Y ejecutemos el comando</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl apply -f nginx-deploy.yaml
</code></pre></div>
<p>Si ahora ejecutamos nuestros comandos <em>get pods y describe</em> veremos como tenemos otra versión ya desplegada.</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-21.18.58.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<ol start="2">
<li>Es posible, al igual que hicimos antes, usar el comando edit, para modificar el estado actual que está en la api de kubernetes (en teoría funciona pero a mi me da problemas, aviso por si acaso)</li>
</ol>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl edit deploy nginx-deploy
</code></pre></div>
<ol start="3">
<li>Tenemos la opción de modificar directamente la imagen de un deployment con la opción <em>set</em></li>
</ol>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl <span class="token builtin class-name">set</span> image deployments/nginx-deploy nginx-pod<span class="token operator">=</span>nginx:latest
</code></pre></div>
<p>Este comando indicamos que modifique la imagen dentro del <strong>deployment/nginx-deploy</strong> de los pods con nombre <strong>nginx-pod</strong> usando la imagen <strong>nginx-latest</strong>. Si nos fijamos en nuestra definición de nuestro objeto <em>deployment</em> el nombre que yo le he puesto es el de <strong>nginx-pod</strong></p>
<p>Si comprobaramos nuestros ya típicos <em>get pods y describe</em> otra vez veríamos lo siguiente</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-21.26.13.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Otra vez de nuevo nos ha cambiado la versión correctamente.</p>
<p>Como tal tenemos otro comando para comprobar que la actualización ha ido correctamente que es el comando <em>rollout</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl rollout status deployment nginx-deploy
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-21.28.29.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Este comando nos confirma que la actualización ha ido correctamente.</p>
<h4 id="haciendorollback">Haciendo rollback</h4>
<p>Ya hemos visto como actualizar pero... ¿y si todo se ha roto al actualizar y queremos volver atras? Pues en este caso es tan sencillo como...</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl rollout undo deployment nginx-deploy
</code></pre></div>
<p>Et voilá</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-16-a-las-21.31.00.png" alt="Docker XII - Kubernetes VII: Escalando PODS"/></p>
<p>Nuestra versión vuelve a ser la de <strong>nginx:stable</strong>. Creo que en este caso no tengo mucho más que decir, solo comentar que esto se podría automatizar con los <em>healthchecks</em> que vimos en post anteriores (revisar la doc oficial que yo no he entrado en tanto detalle de momento), esto han sido unos primeros pasos para ver como lo podemos hacer nosotros todo manualmente.</p>
<p>No me enrollo más, espero que os haya gustado este post con el escalado y el rollback de nuestras aplicaciones, sin mucho más nos vemos en el siguienteeeee un abrazoooor</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker XI - Kubernetes VI: Exponiendo aplicaciones al exterior con el Objeto Service]]></title><description><![CDATA[En el post anterior ya incluimos el concepto de service, en este post
explicaremos realmente lo que es.
Hasta ahora habíamos estado trabajando con objetos de tipo POD, si hacemos un
poco de memoría o volvieramos a probar veriamos como no realmente no podíamos
acceder realmente desde nuestro equipo a ningún contenedor a no ser que
hicieramos algún mapeo externo de puertos o similar, pues bien para esto son los
objetos de tipo de Service, estos objetos entre otras cosas nos permiten exponer
hacía]]></description><link>https://jlgarcia.fulldev.ninja/docker-xi-kubernetes-vi-service/</link><guid isPermaLink="false">Ghost__Post__5ffafa8ea6c0f5058bff4cc9</guid><category><![CDATA[Docker]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 25 Jan 2021 09:57:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-2.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-2.jpg" alt="Docker XI - Kubernetes VI: Exponiendo aplicaciones al exterior con el Objeto Service"/><p>En el post anterior ya incluimos el concepto de <em>service</em>, en este post explicaremos realmente lo que es.</p>
<p>Hasta ahora habíamos estado trabajando con objetos de tipo POD, si hacemos un poco de memoría o volvieramos a probar veriamos como no realmente no podíamos acceder realmente desde nuestro equipo a ningún contenedor a no ser que hicieramos algún mapeo externo de puertos o similar, pues bien para esto son los objetos de tipo de <em>Service</em>, estos objetos entre otras cosas nos permiten exponer hacía afuera los nodos del cluster que nosotros le indiquemos.</p>
<p>Conceptualmente puede ser algún similar a un nginx o por ejemplo si pensamos en cloud podría ser como un API Gateway de AWS (ojo que digo conceptualmente para que entendamos un poco cual es su función). Realmente el objetivo de un objeto <em>service</em> es proveer una dirección o forma estable de acceder a nuestros nodos del cluster, ya que cada vez que se levanten nuestros nodos pueden tener una dirección IP diferente, es más, usar un objeto service realmente no implica necesariamente que expongamos nuestros nodos, podemos simplemente crear una IP interna del cluster para acceder a un conjunto de nodos desde otros nodos, ya depende realmente de nuestras necesidades.</p>
<p>Veamos un ejemplo de configuración de un objeto de tipo <em>service</em>. Para ello lo más fácil es hacer lo mismo que hicimos cuando veiamos los <em>pods</em>, ejecutaremos un comando con el flag <em>dry-run</em> para que no haga nada.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">kubectl expose pod/mario-test --port <span class="token number">8080</span> --type<span class="token operator">=</span>NodePort --dry-run<span class="token operator">=</span>client -o yaml <span class="token operator">></span> mario-service.yaml
</code></pre></div>
<p>Ya hablaremos sobre los tipos por el momento solo ejecutaremos el comando y abrimos el fichero que nos crea</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Service
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>game
<span class="token key atrule">run</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">tier</span><span class="token punctuation">:</span> games
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">protocol</span><span class="token punctuation">:</span> TCP
<span class="token key atrule">targetPort</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">selector</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>game
<span class="token key atrule">run</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">tier</span><span class="token punctuation">:</span> games
<span class="token key atrule">type</span><span class="token punctuation">:</span> NodePort
<span class="token key atrule">status</span><span class="token punctuation">:</span>
<span class="token key atrule">loadBalancer</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Vemos como ahora la propiedad <em>kind</em> cambia y ahora es <strong>Service</strong>, pero hablemos un poco más en específico de lo que estamos viendo.</p>
<p>Primero de todo tenemos <em>metadata</em>, que como información relevante tiene:</p>
<ul>
<li><strong>labels</strong>: Conjunto de clave valor que en un principio es meramente informativo y que podemos incluir los que queramos. Esto según el caso puede servir como identificador, por ejemplo, en mi caso tiene los mismos labels que mi pod, en vuestro caso puede contener otros si habéis puesto algo distinto en los labels. Podéis hacer la prueba eliminando el pod actual, modificando los labels del fichero pod que estéis usando, creando el pod de nuevo y ejecutando el comando <em>dry-run</em> de nuevo para ver como cambia</li>
<li><strong>name</strong>: El nombre con el que identificaremos el servicio</li>
</ul>
<p>A continuación tenemos <em>spec</em> que al igual que con los pods es donde esta todo lo <em>importante</em>, es decir, lo que queremos crear realmente o que configuración debe llevar, veamoslo un poco en detalle:</p>
<ul>
<li><strong>selector</strong>: Empezamos por este porque nos ayuda a saber donde apunta realmente el service. Si nos fijamos en su contenido debe tener lo mismo que los labels que tiene nuestro pod. Esto es porque realmente esta propiedad es la que se usa para filtrar y encontrar los pods en cuestión. Pensemos que realmente todo esto esta pensado para tener varias instancias del mismo pod, entonces como las identifica el <em>service</em>? Hace uso de los labels que le hemos puesto al pod y con eso filtra o busca los contenedores en cuestión.</li>
<li><strong>type</strong>: Como tal es posible crear 3 tipos de servicio.
<ul>
<li>Tipo <strong>ClusterIP</strong>: Nos proporcionaría una ip fija interna del cluster para todas las instancias de un mismo pod para que el resto de pods puedan hacer uso de ellos</li>
<li>Tipo <strong>NodePort</strong>: Expone hacia el exterior del cluster el conjunto de pods seleccionados.</li>
<li>Tipo <strong>LoadBalancer</strong>: Se usa realmente con kubernetes en producción en algún proveedor cloud que son capaces de hacer uso de esta configuración para integrarlo con sus balanceadores.</li>
</ul>
</li>
<li><strong>ports</strong>: Parte muy importante, en este punto definimos los puertos por los que se puede acceder a nuestro contenedor a través del servicio (bueno y también el protocolo como veis):
<ul>
<li><strong>port</strong>: Puerto interno del cluster por el que el resto de pods pueden acceder a la aplicación que se despliegue en el pod (suele coincidir con targetPort)</li>
<li><strong>targetPort</strong>: Puerto que expone el contenedor o pod de su servicio, este seria al puerto que redireccionará automáticamente el service cuando se accede desde fuera del cluster al pod (suele coincidir con port)</li>
<li><strong>nodePort (opcional)</strong>: Aunque no aparezca ahora mismo tenemos esta opción también que es el puerto que expondra el servicio para acceder al <em>targetPort</em> seleccionado y se usará cuando pongamos el <strong>type=NodePort</strong> como os podéis imaginar. Tiene un rango específico -> 30000-32767. A no ser que lo queramos tener identificado, podemos dejar que el servicio decida de manera random uno dentro de ese rango.</li>
</ul>
</li>
</ul>
<p>Estas serían las configuraciones principales o básicas sobre un <em>Service</em>, como siempre recomiendo ver la documentación para ver los detalles y más configuraciones que nos puedieran interesar -> <a href="https://kubernetes.io/docs/concepts/services-networking/service/">Kubernetes Service</a></p>
<p>Veamos ahora como funciona todo esto, pero antes de continuar comentar que lo que se explica aquí puede dar algún problema o ser distinto según la configuración con la que tengáis levantado minikube o vuestro servicio de kubernetes que estéis usando, en mi caso el ejemplo para el blog lo estoy haciendo en un mac con <em>Docker Desktop</em> por lo que es necesario hacer algún extra para que funcione el <em>Service</em>.</p>
<p>Primero de todo creemos el servicio:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create -f mario-service.yaml
</code></pre></div>
<p>Y una vez creado veamos que tenemos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl get svc
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-12-a-las-21.09.15.png" alt="Docker XI - Kubernetes VI: Exponiendo aplicaciones al exterior con el Objeto Service"/></p>
<p>Como vemos tenemos dos servicios el de <em>kubernetes</em> que es el de por defecto, (de tipo ClusterIP y es el servicio que comunica con el server master de kubernetes) y el que acabamos de crear <em>mario-test</em> de tipo <em>NodePort</em>, es decir, que "técnicamente" deberiamos poder acceder desde nuestra máquina al contenedor en cuestión al que apunta usando el puerto que ha seleccionado kubernetes automáticamente, en mi caso el <strong>32142</strong></p>
<p>Si intentamos acceder a través del navegador con <strong>localhost:32142</strong> deberíamos poder ver el fork de <em>Mario</em></p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-14-a-las-20.09.01.png" alt="Docker XI - Kubernetes VI: Exponiendo aplicaciones al exterior con el Objeto Service"/></p>
<p>He comentado antes el "técnicamente" porque es posible (como es mi caso con el entorno de ejemplo) que aún asi no podamos acceder, ahora veremos porque.</p>
<p>Kubernetes como tal no está pensado para funcionar en un portatil o en el equipo típico de sobremesa, es decir, si estas usando la aplicación "Docker Desktop" para jugar con kubernetes (en lugar de simplemente tener el Docker Engine) esto no te va a funcionar, es decir, si no has creado una máquina virtual para esto o no estas usando un servidor real de kubernetes seguirás sin poder acceder. Para poder acceder tendremos que hacer uso de un <em>port-forward</em>. <strong>REPITO ESTO NO SE TIENE QUE HACER EN UN ENTORNO EN PRODUCCIÓN A NO SER QUE SEPAS LO QUE HACES, LO HACEMOS POR NECESIDAD EN NUESTRO ENTORNO DE PRUEBAS PARA ACCEDER AL CONTENEDOR</strong></p>
<p>Para este caso no es necesario que tengamos un service creado ni nada (pongo esta opción solo para que podamos acceder a nuestro contenedor, no tiene que ver con nuestro uso de services). Lo que haremos será ejecutar</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl port-forward mario-test <span class="token number">8000</span>:8080
</code></pre></div>
<p>Con este comando simplemente <strong>hacemos una redirección de nuestro puerto local 8000 al puerto 8080 del pod mario-test</strong>. Al ejecutar este comando deberíamos ver algo similar a esto</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-14-a-las-20.13.32.png" alt="Docker XI - Kubernetes VI: Exponiendo aplicaciones al exterior con el Objeto Service"/></p>
<p>Y si entramos con un navegador a <strong>localhost:8000</strong> veremos como nos aparece la aplicación y en la consola (donde debe permanecer en ejecución el port-forward) esta gestionando conexiones del puerto 8000</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-14-a-las-20.15.05.png" alt="Docker XI - Kubernetes VI: Exponiendo aplicaciones al exterior con el Objeto Service"/></p>
<p>Tras el inciso para mostrar como acceder en el caso de que no tengas un entorno similar al de producción de kubernetes, continuamos un poco hablando de los tipos de <em>Service</em></p>
<p>En el ejemplo anterior hemos visto como sería un service de tipo <em>NodePort</em>, he querido mostrar este ejemplo porque es similar al de <em>ClusterIP</em> pero nos permite comprobar el acceso sin complicarnos creando más pods ni nada así.<br>
Si pensamos en el tipo <em>ClusterIP</em>, nos quedaremos con que nos permite acceder a un conjunto de pods usando una misma dirección IP o <em>nombre de host</em> desde dentro del propio cluster para que puedan tener comunicación entre sí, sobre todo cuando tenemos intención de crear más de una instancia de un mismo pod (que sería para lo que usamos kubernetes realmente creo yo jejejeje). Hago incapié en esto del <em>hostname</em>, como tal el nombre del service es también el hostname que podremos usar para acceder al conjunto de pods dentro del cluster.</br></p>
<p>Si, por ejemplo, eliminamos el servicio actual</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl delete svc mario-test
</code></pre></div>
<p>Cambiamos el fichero del <em>service</em> indicandole que es de tipo <em>ClusterIP</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Service
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>game
<span class="token key atrule">run</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">tier</span><span class="token punctuation">:</span> games
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>service
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">protocol</span><span class="token punctuation">:</span> TCP
<span class="token key atrule">targetPort</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">selector</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>game
<span class="token key atrule">run</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">tier</span><span class="token punctuation">:</span> games
<span class="token key atrule">type</span><span class="token punctuation">:</span> ClusterIP <<span class="token punctuation">-</span><span class="token punctuation">-</span> cambiamos esta linea
<span class="token key atrule">status</span><span class="token punctuation">:</span>
<span class="token key atrule">loadBalancer</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Y ejecutamos de nuevo el create</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create -f mario-service.yaml
</code></pre></div>
<p>Veremos como haciendo un get de los servicios tenemos otro de tipo <em>ClusterIP</em>. Como detalle fijarse en que ahora en puertos solo nos aparece uno, es decir, solo nos aparece el puerto <em>interno</em> del cluster, es decir, al que redireccionariamos si usáramos el tipo <em>NodePort</em>.</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-14-a-las-20.26.34.png" alt="Docker XI - Kubernetes VI: Exponiendo aplicaciones al exterior con el Objeto Service"/></p>
<p>No me extiendo en esta parte porque no tiene mucho más, si quisierais probarlo solo es necesario crear otro pod, acceder al contenedor y lanzar una petición, como ejemplo rápido</p>
<p>Ejecutamos y nos adjuntamos a la consola</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl run --rm -i --tty alpine-pod --image<span class="token operator">=</span>alpine --restart<span class="token operator">=</span>Never -- <span class="token function">sh</span>
</code></pre></div>
<p>Con esto le indicamos que queremos un pod con el nombre <em>alpine-pod</em>, que use la imagen de docker de <em>alpine</em>. Los extras como el <em>rm</em> que se elimine al terminar la ejecución y el último relevante es el sh para acceder a la consola.</p>
<p>Si todo funciona os aparecera un promt para ejecutar comandos</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-14-a-las-20.47.25.png" alt="Docker XI - Kubernetes VI: Exponiendo aplicaciones al exterior con el Objeto Service"/></p>
<p>Ejecutamos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">wget</span> mario-service:8080
</code></pre></div>
<p>Y tenemos que se ha bajado el index.html de nuestro contenedor</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-14-a-las-20.48.05.png" alt="Docker XI - Kubernetes VI: Exponiendo aplicaciones al exterior con el Objeto Service"/></p>
<p>(para salir con ejecutar <em>exit</em> vale ;) y veremos como nos aviso de que elimina el pod )</p>
<p>Es una prueba muy rápida pero creo que es suficiente para entender el funcionamiento de un service de tipo <em>ClusterIP</em>, aquí tenemos que plantearnos que en un entorno en producción lo más probable es que tengamos mas de un contenedor del mismo tipo de POD.</p>
<p>Nos faltaría por ver el tipo <strong>loadBalancer</strong> pero como esta relacionado más con entornos <em>cloud</em> lo veremos más adelante, sin mucho más se termina este post nos vemos en el siguiente un abrazooooor</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker X - Kubernetes V: Salud de nuestros PODS]]></title><description><![CDATA[En este posts veremos 2 configuraciónes básicas para manejar el estado de salud
de nuestros pods. Con estas configuraciones kubernetes de manera automática
puede por ejemplo reiniciar un pod o no mandarle tráfico.
Para esto tenemos estas 2 propiedades:
* livenessProbe: Si esta sonda falla kubernetes puede por ejemplo reiniciar el
pod. Es el típico health que solemos tener en otros servicios. Como tal se
puede configurar que tiene que hacer kubernetes cuando la sonda falla, como
por e]]></description><link>https://jlgarcia.fulldev.ninja/docker-x-kubernetes-v-salud-de-nuestros-pods/</link><guid isPermaLink="false">Ghost__Post__5ffae3e3a6c0f5058bff4cba</guid><category><![CDATA[Docker]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 19 Jan 2021 09:19:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-1.jpg" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/><p>En este posts veremos 2 configuraciónes básicas para manejar el estado de salud de nuestros pods. Con estas configuraciones kubernetes de manera automática puede por ejemplo reiniciar un pod o no mandarle tráfico.</p>
<p>Para esto tenemos estas 2 propiedades:</p>
<ul>
<li><strong>livenessProbe</strong>: Si esta sonda falla kubernetes puede por ejemplo reiniciar el pod. Es el típico <em>health</em> que solemos tener en otros servicios. Como tal se puede configurar que tiene que hacer kubernetes cuando la sonda falla, como por ejemplo cuantos errores debe dar antes de reiniciar y cosas así</li>
<li><strong>readinessProbe</strong>: Hasta que esta sonda no funcione kubernetes no enviaría tráfico al POD (no lo añadiría al objeto <em>service</em> que veremos más adelante lo que es) y en el caso de que empiece a devolver errores dejaría de enviarle tráfico (lo quitaría del objeto <em>service</em>)</li>
</ul>
<p>Para ver como funciona esto, lo primero eliminaremos el pod actual si lo tenemos todavía activo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl delete pods mario-test
</code></pre></div>
<p>Y modificaremos el fichero del POD añadiendo estas propiedades. Primero con la de liveness</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">run</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">containers</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> pengbai/docker<span class="token punctuation">-</span>supermario<span class="token punctuation">:</span>latest
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">name</span><span class="token punctuation">:</span> game // <<span class="token punctuation">-</span> Esto es nuevo
<span class="token key atrule">resources</span><span class="token punctuation">:</span>
<span class="token key atrule">requests</span><span class="token punctuation">:</span>
<span class="token key atrule">cpu</span><span class="token punctuation">:</span> 50m
<span class="token key atrule">memory</span><span class="token punctuation">:</span> 64M
<span class="token key atrule">limits</span><span class="token punctuation">:</span>
<span class="token key atrule">cpu</span><span class="token punctuation">:</span> 50m
<span class="token key atrule">memory</span><span class="token punctuation">:</span> 64M
<span class="token key atrule">livenessProbe</span><span class="token punctuation">:</span>
<span class="token key atrule">httpGet</span><span class="token punctuation">:</span>
<span class="token key atrule">path</span><span class="token punctuation">:</span> /fake
<span class="token key atrule">port</span><span class="token punctuation">:</span> game
<span class="token key atrule">dnsPolicy</span><span class="token punctuation">:</span> ClusterFirst
<span class="token key atrule">restartPolicy</span><span class="token punctuation">:</span> Always
<span class="token key atrule">status</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Antes de hablar de la configuraciónd de la sonda comentar que hemos añadido un nombre al puerto en cuestión del contenedor para que nos sea más fácil hacer referencia a él y no tener que cambiarlo en un montón de sitios si de repente cambiamos el puerto.</p>
<p>Además del nombre del puerto hemos añadido la propiedad <em>livenessProbe</em>, dentro de esta propiedad podemos incluir comandos, peticiones a http y otras cosas que nos pueden resultar útiles para realizar la comprobación del estado de salud (al final del post pondré el link de la documentación para ampliar información). En nuestro caso hemos añadido una petición <strong>get</strong> a un path <strong>/fake</strong> que realmente no existe, para que veamos que ocurre.</p>
<p>Guardamos y creamos el pod como hasta ahora</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create -f mario.yaml
</code></pre></div>
<p>Y veamos que pasa si ejecutamos nuestro comando <strong>get pods</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl get pods
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-09-a-las-14.22.34-1.png" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/></p>
<p>En un principio parecería que todo esta correcto pero si esperamos veremos como se producen cambios, normalmente a los 30 segundos empezaremos a ver diferencias</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-10-a-las-13.19.01.png" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/></p>
<p>Vemos como se ha reiniciado una vez y si esperamos 5 loops tendremos este error y también ha cambiado el número de contenedores <em>READY</em> a 0</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-10-a-las-13.20.50.png" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/></p>
<p>Por último si comprobamos el describe del pod en cuestión podremos ver el registro de los eventos que se han ido sucediendo</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-10-a-las-12.53.08.png" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/></p>
<p>Este sería el caso usando <em>livenessProbe</em>, como tal hemos visto como ha intentando reiniciar cada 30 segundos hasta que ha confirmado que no funciona. Si analizamos el describe un poco más arriba veremos como en la configuración por defecto se comprueba cada 10 segundos con un máximo de 3 fallos hasta que reinicia (estas son serian algunas de los campos que podemos configurar)</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-10-a-las-12.52.55.png" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/></p>
<p>Hagamos la prueba ahora usando <strong>readinessProbe</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">run</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">containers</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> pengbai/docker<span class="token punctuation">-</span>supermario<span class="token punctuation">:</span>latest
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">name</span><span class="token punctuation">:</span> game
<span class="token key atrule">resources</span><span class="token punctuation">:</span>
<span class="token key atrule">requests</span><span class="token punctuation">:</span>
<span class="token key atrule">cpu</span><span class="token punctuation">:</span> 50m
<span class="token key atrule">memory</span><span class="token punctuation">:</span> 64M
<span class="token key atrule">limits</span><span class="token punctuation">:</span>
<span class="token key atrule">cpu</span><span class="token punctuation">:</span> 50m
<span class="token key atrule">memory</span><span class="token punctuation">:</span> 64M
<span class="token key atrule">readinessProbe</span><span class="token punctuation">:</span>
<span class="token key atrule">httpGet</span><span class="token punctuation">:</span>
<span class="token key atrule">path</span><span class="token punctuation">:</span> /fake
<span class="token key atrule">port</span><span class="token punctuation">:</span> game
<span class="token key atrule">dnsPolicy</span><span class="token punctuation">:</span> ClusterFirst
<span class="token key atrule">restartPolicy</span><span class="token punctuation">:</span> Always
<span class="token key atrule">status</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Este caso si ejecutamos el <em>get pods</em> podemos ver como ya al inicio cambia un poco, nunca tenemos el pod en <em>READY</em>, si nos fijamos estamos siempre en <em>0/1</em></p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-10-a-las-13.31.21.png" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/></p>
<p>Y trás algunos reinicios, si esperamos 3 minutos tenemos un error</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-10-a-las-13.33.59.png" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/></p>
<p>Por último veamos que tenemos en nuestro <em>describe</em>. Primero podemos ver la configuración por defecto (la misma que con <em>liveness</em>):</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-10-a-las-13.35.37.png" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/></p>
<p>Y si nos vamos a los eventos que han ido sucediendo tenemos</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-10-a-las-13.36.03.png" alt="Docker X - Kubernetes V: Salud de nuestros PODS"/></p>
<p>Vemos como ha intendado varias veces acceder a el y no ha sido capaz devolviendonos el error que ya hemos visto.</p>
<p>Estas han sido dos configuraciones básicas que podemos hacer, en la documentación <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/">oficial</a> tenemos más información sobre la configuración, a que afecta realmente cada caso y otro probe más que es el de <strong>startup</strong>, recomiendo encarecidamente leerla y hacer más pruebas para ver las posibilidades que nos ofrecen los checks de estado de salud sobre nuestros pods.</p>
<p>Y hasta aquí este post, nos vemos en el siguiente un abrazoooorrrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker IX - Kubernetes IV: Definiendo recursos de hardware]]></title><description><![CDATA[En el post anterior vimos una configuración muy básica de los pods, pero como os
imaginaréis tenemos más posibilidades interesantes que estaria bien que
tuvieramos en cuenta. Una de ellas es la configuración/limitación de recursos.
Cuando usamos pods pero no indicamos ningún límite de recursos de hardware, nos
encontrariamos con estos 2 escenarios:
* Tener unos límites definidos por defecto dentro del cluster de kubernetes
* Usar los recursos sin límite (no recomendado para nada, si sabemos ]]></description><link>https://jlgarcia.fulldev.ninja/docker-ix-kubernetes-iv-definiendo-recursos/</link><guid isPermaLink="false">Ghost__Post__5ff96d70a6c0f5058bff4c9d</guid><category><![CDATA[Docker]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 11 Jan 2021 09:32:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice.jpg" alt="Docker IX - Kubernetes IV: Definiendo recursos de hardware"/><p>En el post anterior vimos una configuración muy básica de los pods, pero como os imaginaréis tenemos más posibilidades interesantes que estaria bien que tuvieramos en cuenta. Una de ellas es <strong>la configuración/limitación de recursos</strong>.</p>
<p>Cuando usamos pods pero no indicamos ningún límite de recursos de hardware, nos encontrariamos con estos 2 escenarios:</p>
<ul>
<li>Tener unos límites definidos por defecto dentro del cluster de kubernetes</li>
<li>Usar los recursos sin límite (no recomendado para nada, si sabemos de sobra que no usaremos en ningun caso todo el hardware disponible nos podemos arriesgar, pero si tenemos intención de aumentar contenedores en el futuro esto puede convertirse en un problema importante)</li>
</ul>
<p>Lo ideal es siempre definir unos recursos específicos para cada elemento, así kubernetes puede distribuir los contenedores y los recursos de manera mucho más eficiente.<br>
Para ello podemos/tenemos que añadir dos nuevas propiedades en nuestros pods, veamos un ejemplo.</br></p>
<p>Como usaremos el mismo pod que hemos estado usando actualmente lo primero que haremos será borrar los pods que tenemos actualmente, para ello es suficiente con ejecutar el siguiente comando por cada pod que queramos eliminar:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">// para obtener los pods actuales
kubectl get pods
// para eliminar un post específico
kubectl delete pods nombreDelContainer
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-09-a-las-13.57.29.png" alt="Docker IX - Kubernetes IV: Definiendo recursos de hardware"/></p>
<p>Como vemos en la imagen la consola nos confirma su eliminación.<br>
Ahora añadamos las opciones para limitar o específicar los recursos:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">run</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">containers</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> pengbai/docker<span class="token punctuation">-</span>supermario<span class="token punctuation">:</span>latest
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">resources</span><span class="token punctuation">:</span>
<span class="token key atrule">requests</span><span class="token punctuation">:</span>
<span class="token key atrule">cpu</span><span class="token punctuation">:</span> 50m
<span class="token key atrule">memory</span><span class="token punctuation">:</span> 64M
<span class="token key atrule">limits</span><span class="token punctuation">:</span>
<span class="token key atrule">cpu</span><span class="token punctuation">:</span> 50m
<span class="token key atrule">memory</span><span class="token punctuation">:</span> 64M
<span class="token key atrule">dnsPolicy</span><span class="token punctuation">:</span> ClusterFirst
<span class="token key atrule">restartPolicy</span><span class="token punctuation">:</span> Always
<span class="token key atrule">status</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Si nos fijamos en nuestro fichero pod hemos añadido nuevas propiedades dentro de <em>resources</em>, hemos añadido:</p>
<ul>
<li><strong>requests</strong>: Con esta opción le indicamos a kubernetes el mínimo de recursos que debe tener nuestro contenedor. Esto es muy útil para que kubernetes lo situe donde más le convenga.</li>
<li><strong>limits</strong>: Como su nombre indica este es el límite que le estamos indicando a kubernetes que puede usar nuestro contenedor. <strong>IMPORTANTE: si el contenedor se pasa de recursos es posible que kubernetes decida parar el contenedor</strong></li>
</ul>
<p>Para ver en detalle las opciones de CPU y MEMORIA recomienda leerse la documentación al respecto <a href="https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/">Assign cpu resource</a> y <a href="https://kubernetes.io/docs/concepts/configuration/manage-resources-containers">Manage resources containers</a></p>
<p>En nuestro ejemplo le estamos limitando al uso de *50 milliCPU * y <em>64Mb</em>, si por ejemplo le indicaramos algo que no tuviera disponible nuestro cluster, kubernetes lo que haría sería esperar a tener esos recursos disponibles para arrancar el contenedor en cuestión.</p>
<p>Ahora arranquemos nuestro pod:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create -f mario.yml
</code></pre></div>
<p>Y si hacemos un describe de nuestro pod</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">kubectl describe pods mario-test
</code></pre></div>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-09-a-las-14.18.28.png" alt="Docker IX - Kubernetes IV: Definiendo recursos de hardware"/></p>
<p>Podemos ver como todo ha funcionado correctamente y nuestro pod tiene configurado sus recursos.</p>
<p>Ahora cambiemos la configuración para que veamos que pasa cuando le ponemos una cantidad de recursos que no puede asumir. Por ejemplo en mi caso le ponemos que use 64Gb (que mi maquina actual no los tiene)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">creationTimestamp</span><span class="token punctuation">:</span> <span class="token null important">null</span>
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">run</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">containers</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">image</span><span class="token punctuation">:</span> pengbai/docker<span class="token punctuation">-</span>supermario<span class="token punctuation">:</span>latest
<span class="token key atrule">name</span><span class="token punctuation">:</span> mario<span class="token punctuation">-</span>test
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">8080</span>
<span class="token key atrule">resources</span><span class="token punctuation">:</span>
<span class="token key atrule">requests</span><span class="token punctuation">:</span>
<span class="token key atrule">cpu</span><span class="token punctuation">:</span> 50m
<span class="token key atrule">memory</span><span class="token punctuation">:</span> 64G
<span class="token key atrule">limits</span><span class="token punctuation">:</span>
<span class="token key atrule">cpu</span><span class="token punctuation">:</span> 50m
<span class="token key atrule">memory</span><span class="token punctuation">:</span> 64G
<span class="token key atrule">dnsPolicy</span><span class="token punctuation">:</span> ClusterFirst
<span class="token key atrule">restartPolicy</span><span class="token punctuation">:</span> Always
<span class="token key atrule">status</span><span class="token punctuation">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div>
<p>Si ahora borramos el pod que tenemos y creamos este nuevo veamos lo que pasa:</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-09-a-las-14.22.34.png" alt="Docker IX - Kubernetes IV: Definiendo recursos de hardware"/></p>
<p>Nuestro pod se queda con un estado pending permanente, y si vemos la descripción del pod nos indicara el estado y la información de porque no se esta ejecutando, en este caso por falta de memoria</p>
<p><img srcset="/assets/images/2021/01/Captura-de-pantalla-2021-01-09-a-las-14.23.42.png" alt="Docker IX - Kubernetes IV: Definiendo recursos de hardware"/></p>
<p>Como vemos con estas simples propiedades dentro de los pods podemos limitar o indicar los recursos que nuestro contenedor o pod usará (con requests) y la cantidad de hardware que queremos que use como máximo (con limits).</p>
<p>Y hasta aquí lo referente a lo básico de sobre los recursos de nuestros pods, recomiendo leer la documentación para poder hacer un selección más específica de los recursos que queremos que usen nuestros contenedores, sin mucho más nos vemos en el siguiente, un abrazooooooooo</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II]]></title><description><![CDATA[Bien en el post anterior vimos la primera de las opciones para compensar el
problema del maximum call stack que nos podía dar la recursividad. En este post
veremos algunas otras opciones para tener en nuestro arsenal, que cumplen (más o
menos) con la resolución de nuestro problema aunque alguna sea bastante lenta y
tengan el handicap de que debemos controlar la asincronía.
Usando setTimeout
En este caso vamos a jugar con el conocido setTimeout, en este punto es mejor
que estemos familiarizados ]]></description><link>https://jlgarcia.fulldev.ninja/js-algoritmos-y-estructuras-de-datos-vii-la-recursividad-iii/</link><guid isPermaLink="false">Ghost__Post__5fd65ddfa6c0f5058bff49a1</guid><category><![CDATA[algoritmos]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 28 Dec 2020 09:30:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640-1.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/><p>Bien en el post anterior vimos la primera de las opciones para compensar el problema del <em>maximum call stack</em> que nos podía dar la recursividad. En este post veremos algunas otras opciones para tener en nuestro arsenal, que cumplen (más o menos) con la resolución de nuestro problema aunque alguna sea bastante lenta y tengan el handicap de que debemos controlar la asincronía.</p>
<h3 id="usandosettimeout">Usando setTimeout</h3>
<p>En este caso vamos a jugar con el conocido <strong>setTimeout</strong>, en este punto es mejor que estemos familiarizados con el <strong>event-loop</strong> (<a href="https://blog.insiderattack.net/event-loop-and-the-big-picture-nodejs-event-loop-part-1-1cb67a182810">recomiendo leer estos posts</a>)</p>
<p>Usaremos este ejemplo, cambia un poco lo que teniamos antes, pero es por intentar seguir con el mismo concepto del sumatorio</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> accum <span class="token operator">=</span> <span class="token number">0</span>
<span class="token keyword">let</span> number <span class="token operator">=</span> <span class="token number">5</span>
<span class="token keyword">function</span> <span class="token function">addTo</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>number <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>accum<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
accum <span class="token operator">=</span> number <span class="token operator">+</span> accum
number<span class="token operator">--</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">finish</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Finished'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Como vemos tenemos nuestra función <strong>addTo</strong> que si el número no es 0 pasa por un <strong>setTimeout</strong> con 0. Esto aunque no podamos verlo en la aplicación que lo incluye dentro de la <strong>task queue</strong> lo que hace es incluir el método en la <strong>timers queue</strong> y se ejecutaría según el ciclo de vida habitual de node cuando pase por los <strong>timers</strong> resueltos.</p>
<p>Veamos un poco lo que pasa cuando ejecutamos esto dentro de <strong>jv9000</strong> <strong>(OJO que esto no funciona en la web tengo un fork modificado para permitir esto y otras cosas)</strong></p>
<ol>
<li>
<p>Incluye en el call stack la primera ejecución de <strong>addTo</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-20.24.06.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></p>
</li>
<li>
<p>Como <em>number</em> no es 0 se ejecuta el <em>setTimeout</em>, es decir, incluye la función anónima dentro de la <em>timers queue</em>, que para nosotros en nuestro visualizador esta dentro de la <em>task queue</em><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-20.24.21.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></p>
</li>
<li>
<p>Importante, el paso anterior ha pasado como a un segundo plano dentro del event loop, por lo que para nosotros ha terminado la ejecución de <strong>addTo</strong> por lo que ya la podemos sacar del <strong>call stack</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-20.24.36.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></p>
</li>
<li>
<p>El loop continua y le toca a la función finish.<br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-20.25.02.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"><br>
Importante en este punto darse cuenta de que ha entrado la función finish al <em>call stack</em> se ha ejecutado y ha salido, sin que todavía hayamos tocado lo que tenemos dentro de <em>task queue</em></br></img></br></p>
</li>
<li>
<p>Una vez ejecutada la función <em>finish</em> ya le toca el turno a comprobar <em>task</em>, al ver que tenemos algo lo pasa al <em>call stack</em> y lo ejecuta<br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-20.25.43.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></p>
</li>
<li>
<p>Al ejecutarlo dentro del call stack, lo que tenemos de nuevo es otra ejecución de <em>addTo</em>, que repite la operación incluye en la <em>task queue</em> la función anónima del timeout<br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-20.37.26.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></p>
</li>
</ol>
<p>Y el proceso se repite <strong>n</strong> veces hasta que se cumple el <strong>number === 0</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-20.55.37.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></p>
<p>Donde terminaría nuestra ejecución. Como vemos aquí tenemos otro caso donde evitamos que la cola de llamadas se llene.</p>
<h3 id="usandosetimmediate">Usando setImmediate</h3>
<p>Usando <strong>setImmediate</strong> es similar al setTimeout pero tiene menos pasos, en el caso anterior nuestra ejecución pasa por incluirse en la cola de task, comprobar el tiempo, ver que ha terminado incluirlo en el call stack y ejecutarlo. Al final son bastantes pasos. Sin embargo el <strong>setImmediate</strong> tiene su propia cola y se ejecutan al momento tras los eventos de I/O por lo que puede ser más rápido en un entorno recursivo. Veamos rápidamente la diferencia:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> accum <span class="token operator">=</span> <span class="token number">0</span>
<span class="token keyword">let</span> number <span class="token operator">=</span> <span class="token number">5</span>
<span class="token keyword">function</span> <span class="token function">addTo</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>number <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>accum<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
<span class="token function">setImmediate</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
accum <span class="token operator">=</span> number <span class="token operator">+</span> accum
number<span class="token operator">--</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">finish</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Finished'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<ol>
<li>Al igual que antes se ejecuta la primera vez <strong>addTo</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-21.09.51.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></li>
<li>Al igual que antes pasa al finish, pero fijemonos que no tenemos en la cola de <em>task</em>, es decir, no estamos pendientes de que realmente termine nada.<br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-21.10.03.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></li>
<li>De repente, si continuaramos ejecutando vemos como ha desaparecido todo y de repente aparece un método anónimo en nuestro call stack, que no es otro que la ejecución de lo que tenemos dentro del <em>setImmediate</em><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-21.10.23.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></li>
<li>Y al igual que antes, este ejecutaría de nuevo nuestra función <em>addTo</em><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-21.10.32.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></li>
</ol>
<p>Este proceso se repetiría, veriamos como entra <em>anonymous</em>, luego <em>addTo</em>, termina <em>addTo</em> y desaparece, termina <em>anonymous</em> y desaparece, y en el siguiente ciclo todo se repite, hasta que coincide con <strong>number===0</strong> que hace que se termine<br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-21.13.54.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></p>
<p>Como vemos es bastante similar al proceso con <em>setTimeout</em> pero con menos pasos, esto no quiere decir que tenga que ser siempre más rápido, a fin de cuentas, ambos pasan por el event loop casi de la misma forma.</p>
<h3 id="usandoprocessnexttick">Usando process.nextTick</h3>
<p>Por último veremos como será nuestra solución usando <strong>process.nextTick()</strong>. En este caso todo es igual que con setImmediate:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">let</span> accum <span class="token operator">=</span> <span class="token number">0</span>
<span class="token keyword">let</span> number <span class="token operator">=</span> <span class="token number">5</span>
<span class="token keyword">function</span> <span class="token function">addTo</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>number <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>accum<span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
process<span class="token punctuation">.</span><span class="token function">nextTick</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
accum <span class="token operator">=</span> number <span class="token operator">+</span> accum
number<span class="token operator">--</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">finish</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Finished'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<p>En este ejemplo me ahorraré las imágenes ya que visualmente sigue el mismo proceso que setImmediate:</p>
<ol>
<li>Se ejecuta la primera vez <strong>addTo</strong></li>
<li>A continuación finish</li>
<li>Anonymous (lo que está dentro de nextTick)</li>
<li><strong>addTo</strong>....</li>
<li>y el proceso se repite</li>
</ol>
<p>Usando <strong>process.nextTick</strong>, tenemos otra solución pero en este caso, el beneficio es la velocidad, si echamos un vistazo a como se procesan las colas:<br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-21-a-las-21.26.21.png" alt="JS Algoritmos y Estructuras de datos VII: La recursividad III - Resolviendo problemas II"/></br></p>
<p>Podremos ver como nextTick se ejecuta tras cada <em>hito</em> dentro del loop, lo que significa que no tenemos que repetir el ciclo de vida del loop para volver a encontrarnos con el <em>nextTick</em>, como ocurre con los timers o el <em>setImmediate</em>.</p>
<p>Con esto de la recursión realmente lo que quería era mostrar un poco como solucionar problemas de <em>maximum call stack</em> y que se viera un poco que ocurre por dentro del event loop que no está de más tenerlo a veces en cuenta cuando tenemos ciertos problemas.</p>
<p>En siguientes posts de esta serie empezaremos con los algoritmos de búsqueda. Otro tema bastante interesante creo yo. Sin más, nos vemos en el siguiente un abrazoooooo</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I]]></title><description><![CDATA[Ya vimos en el post anterior cual es el problema principal que podemos tener en
JavaScript a la hora de usar la recursividad. En un primer momento lo más
probable es que nunca nos encontremos con este problema a no ser que trabajemos
con una gran cantidad de datos, pero aún así, creo que ver como se soluciona
este problema puede hacernos entender algunas cosas del funcionamiento de
Javascript y como podemos usarlas para cualquier otro problema que nos
encontremos.
Para resolver el problema de "]]></description><link>https://jlgarcia.fulldev.ninja/js-algoritmos-y-estructuras-de-datos-vi-la-recursividad-y-como-resolver-el-problema/</link><guid isPermaLink="false">Ghost__Post__5fbc0b8ba6c0f5058bff47fa</guid><category><![CDATA[javascript]]></category><category><![CDATA[algoritmos]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 21 Dec 2020 10:00:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/><p>Ya vimos en el post anterior cual es el problema principal que podemos tener en JavaScript a la hora de usar la recursividad. En un primer momento lo más probable es que nunca nos encontremos con este problema a no ser que trabajemos con una gran cantidad de datos, pero aún así, creo que ver como se soluciona este problema puede hacernos entender algunas cosas del funcionamiento de Javascript y como podemos usarlas para cualquier otro problema que nos encontremos.</p>
<p>Para resolver el problema de <em>"Maximum call stack..."</em> existen varias formas, veremos la mayoría aunque alguna puede que no me guste mucho.</p>
<p>Vamos con la primera <strong>Trampoline</strong></p>
<h3 id="trampoline">Trampoline</h3>
<p>Esta se fue extendiendo como una buena posibilidad para resolver el problema, pero personalmente a mí no me convence demasiado, creo que nos salimos un poco de la pureza del concepto de la recursividad pensando en su planteamiento más funcional. Veamos el código en cuestión:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">trampoline</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">fn</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token function">fn</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token keyword">typeof</span> result <span class="token operator">===</span> <span class="token string">'function'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
result <span class="token operator">=</span> <span class="token function">result</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> result
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">addTo</span><span class="token punctuation">(</span><span class="token parameter">number<span class="token punctuation">,</span> accum <span class="token operator">=</span> <span class="token number">0</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>number <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> accum
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">addTo</span><span class="token punctuation">(</span>number <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> number <span class="token operator">+</span> accum<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">finish</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Finished'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">trampoline</span><span class="token punctuation">(</span>addTo<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Más de uno se hará una idea de lo que realmente estamos haciendo en este caso y como cambia con respecto al ejemplo del post anterior sobre recursividad.<br>
En este ejemplo tenemos una función <strong>addTo</strong> que no se llama a si misma, si no que, según el caso llama a una función anónima que la vuelve a llamar. Pero claro no podemos llamar solo a la función <strong>addTo</strong> ya que en la primera ejecución simplemente devolvería una función que no se ejecuta y terminaría nuestro programa. Lo que hacemos es crear una función <strong>trampoline</strong> que encapsularía cualquier otra donde queramos usar la recursividad. Esta función lo que hace es controlar si la respuesta es una función que debemos que espera ejecutarse o no, en resumen, trampoline es una función que se encarga o de devolver un resultado si se ha cumplido nuestro <em>caso base</em> o de ejecutar de nuevo la función, veamos ahora lo que pasa en nuestro <em>call stack</em>.</br></p>
<ol>
<li><strong>Se ejecuta <em>trampoline</em></strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.21.36.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></li>
</ol>
<p>En cuanto a ejecutar, me refiero a, entre en el call stack y se ejecuta directamente.<br>
Esto es una función con currificación, si nos fijamos lo que le pasamos como parámetro a <em>trampoline</em> es la función que queremos ejecutar, es decir, <em>addTo</em>.</br></p>
<ol start="2">
<li><strong>Se ejecuta <em>trampoline(addTo)(5)</em></strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.27.10.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></li>
</ol>
<p>Entra <strong>trampoline(addTo)(5)</strong> al call stack y comienza a ejecutarse, aquí como tenemos un bucle while donde se ejecutan otros métodos, veremos como el call stack crece</p>
<ol start="3">
<li><strong>Se ejecuta por primera vez <em>addTo</em> con el valor 5</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.29.38.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></li>
</ol>
<p>Como vemos estamos dentro de <em>trampoline(addTo)(5)</em> ejecutando <em>addTo(5, 0)</em><br>
Como el valor no es cero retorna la función anónima que ejecutaria de nuevo <em>addTo</em><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.33.21.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></br></p>
<ol start="4">
<li><strong>Se ejecuta la función anónima que a su vez ejecuta <em>addTo(4, 5)</em></strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.34.00.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></li>
</ol>
<p>Esto devuelve de nuevo una función anónima, pero como tal su ejecución termina por lo que <em>addTo</em> sale del call stack<br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.35.45.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></p>
<p>Y lo mismo sucede con la función anónima que su ejecución ha terminado y sale del call stack<br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.36.02.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></p>
<ol start="5">
<li><strong>Como el resultado de todo esto sigue siendo una función nuestro trampoline vuelve a ejecutar la función anónima que ha recibido</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.38.09.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></li>
</ol>
<p>Donde a su vez se ejecuta <strong>addTo(3, 9)</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.38.19.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></p>
<ol start="6">
<li>
<p><strong>Este proceso se repite hasta que el parámetro number === 0 donde termina la ejecución de la función anónima dentro de trampoline</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.40.34.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></p>
</li>
<li>
<p><strong>Se ejecuta el resultado de <em>console.log(trampoline(addTo)(5))</em> que nos muestra 15</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.40.51.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></p>
</li>
<li>
<p><strong>Se ejecuta <em>finish()</em></strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.41.04.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></p>
</li>
</ol>
<p>Entra dentro del call stack</p>
<ol start="9">
<li><strong>Ejecuta el console.log dentro de la función finish</strong><br>
<img srcset="/assets/images/2020/12/Captura-de-pantalla-2020-12-12-a-las-14.41.15.png" alt="JS Algoritmos y Estructuras de datos VI: La recursividad II - Resolviendo problemas I"/></br></li>
</ol>
<p>Y la ejecución de nuestro programa o script termina</p>
<p>Como vemos esto es un <em>truquillo</em> que hace que no saturemos el call stack de ejecuciones pendientes, que cubre la necesidad que tenemos aunque como digo no es algo que me convenza mucho.</p>
<p>Esta es una de las formas que tenemos para evitar el <em>Maximum call stack</em>, en los siguientes post veremos otras posibles soluciones, algunas más sencillas otras más complejas, pero nos serviran para entender del todo como funciona el call stack.</p>
<p>Nos vemos en el siguiente un abrazoooooo</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker VIII - Kubernetes III: Introducción a los PODS]]></title><description><![CDATA[En este post hablaremos que son los pods y como podemos trabajar con ellos.
En el anterior post ya usamos un pod aunque realmente todavía no sabíamos nada
de ellos. Si recordamos un poco cuando hicimos el run donde le indicabamos el
nombre de la imagen que queriamos desplegar, lo que hizo por debajo kubernetes
fué crear algo bajo el namespace pod/mario-test, ¿verdad?... pues bien para
resumir lo que sería realmente un pod es una aplicación o servicio que puede
tener uno o más contenedores y/o vo]]></description><link>https://jlgarcia.fulldev.ninja/docker-vi-kubernetes-iii-pods/</link><guid isPermaLink="false">Ghost__Post__5fafdfdca6c0f5058bff45a7</guid><category><![CDATA[Docker]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 14 Dec 2020 10:00:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-2.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-2.jpg" alt="Docker VIII - Kubernetes III: Introducción a los PODS"/><p>En este post hablaremos que son los pods y como podemos trabajar con ellos.<br>
En el anterior post ya usamos un pod aunque realmente todavía no sabíamos nada de ellos. Si recordamos un poco cuando hicimos el <strong>run</strong> donde le indicabamos el nombre de la imagen que queriamos desplegar, lo que hizo por debajo kubernetes fué crear <em>algo</em> bajo el namespace <strong>pod/mario-test</strong>, ¿verdad?... pues bien para resumir lo que sería realmente <strong>un pod es una aplicación o servicio que puede tener uno o más contenedores y/o volúmenes de disco</strong>. Estos contenedores o aplicaciones están funcionando bajo el mismo namespace de networking, es decir, el conjunto de contenedores tiene la misma IP pero internamente dentro del POD los contenedores son capaces de comunicarse entre sí solo usando <strong>localhost:<port/></strong> (es como si estuvieramos usando docker-compose con varios contenedores). La ip que reciben es privada y solo se puede acceder a través de otros PODS. Técnicamente hablando esto se conoce como que el pod esta funcionando dentro de su propio <strong>cgroup</strong>.</br></p>
<p>Un POD es la unidad mínima de recursos que podemos tener dentro de kubernetes, es decir, al menos necesitaremos un POD para poder ejecutar un contenedor. Cuando se crea un pod, kubernetes lo asigna a uno de los nodos del cluster que tengamos dependiendo de los recursos disponibles y los deseados. En kubernetes cada Pod tiene su propio ciclo de vida y podemos escalarlo o hacer lo que queramos con ellos por lo que se suele desplegar un POD por aplicación.</p>
<p>La declaración de un POD tiene un estilo similar a cuando trabajamos con <em>recetas</em> de <em>docker-compose</em>, es un yaml con un estilo similar a</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
<span class="token key atrule">name</span><span class="token punctuation">:</span> example<span class="token punctuation">-</span>app
<span class="token key atrule">labels</span><span class="token punctuation">:</span>
<span class="token key atrule">app</span><span class="token punctuation">:</span> example<span class="token punctuation">-</span>app
<span class="token key atrule">version</span><span class="token punctuation">:</span> v1
<span class="token key atrule">role</span><span class="token punctuation">:</span> backend
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
<span class="token key atrule">containers</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> java
<span class="token key atrule">image</span><span class="token punctuation">:</span> companyname/java
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">443</span>
<span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /volumes/logs
<span class="token key atrule">name</span><span class="token punctuation">:</span> logs
<span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logger
<span class="token key atrule">image</span><span class="token punctuation">:</span> companyname/logger<span class="token punctuation">:</span>v1.2.3
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">9999</span>
<span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /logs
<span class="token key atrule">name</span><span class="token punctuation">:</span> logs
<span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> monitoring
<span class="token key atrule">image</span><span class="token punctuation">:</span> companyname/monitoring<span class="token punctuation">:</span>v4.5.6
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">1234</span>
</code></pre></div>
<p>Donde como vemos tenemos la versión de la api, el tipo(pod obviamente), metadatos y spec donde declaramos los containers y su configuración deseada (esos campos son los mínimos necesarios). OJO esto es una forma declarativa de decirle a Kubernetes que es lo que queremos, luego el en su ciclo de vida, cuando toque comparará el estado actual con el deseado y hará los cambios necesarios para cumplir con lo solicitado, como por ejemplo en el caso de que no existan los contenedores los creará al igual que vimos en el post anterior.</p>
<p>Esto es realmente lo que hace kubectl cuando le enviamos el comando en el post anterior:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl run mario-test --image<span class="token operator">=</span>pengbai/docker-supermario:latest --port<span class="token operator">=</span><span class="token number">8080</span>
</code></pre></div>
<p>Usemos un truco para poder ver que es lo que realmente hace el comando, si ejecutamos este comando:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl run mario-test --image<span class="token operator">=</span>pengbai/docker-supermario:latest --port<span class="token operator">=</span><span class="token number">8080</span> --dry-run<span class="token operator">=</span>client -o yaml
</code></pre></div>
<p>Deberiamos ver algo como esto:</p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-16-a-las-20.15.05.png" alt="Docker VIII - Kubernetes III: Introducción a los PODS"/></p>
<p>Esto es lo que realmente esta enviando el comando, donde a modo de resumen rápido tenemos lo siguiente:</p>
<ul>
<li><strong>apiVersion</strong>: versión de la api de kubernetes</li>
<li><strong>kind</strong>: como sabemos estamos ahora mismo trabajando con Pods</li>
<li><strong>metadata.creationTimestamp</strong>: Como realmente no ha sido creado no nos aparece ningún timestamp (supongamos que esta es la especificación que mantiene kubernetes para comparar con la que le mandemos nosotros por eso tiene timestamp)</li>
<li><strong>metadata.labels</strong>: Aquí podemos incluir todo tipo de información útil, como el entorno, al final lo utilizariamos para identificar de alguna manera este POD, su finalidad....</li>
<li><strong>name</strong>: Identificador único del POD</li>
<li><strong>spec</strong>: Donde realmente se encuentra toda la información de los contenedores o lo que sea que este incluido en este pod</li>
</ul>
<p>Para terminar de comprobar que no estoy mintiendo hagamos lo siguiente, vamos a crear un fichero yaml con esta configuración y lanzarsela a kubernetes a ver que pasa. Para ello lo primero creamos el fichero (OJO con el nombre que tiene un 2):</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl run mario-test-2 --image<span class="token operator">=</span>pengbai/docker-supermario:latest --port<span class="token operator">=</span><span class="token number">8080</span> --dry-run<span class="token operator">=</span>client -o yaml <span class="token operator">></span> mario.yaml
</code></pre></div>
<p>Esto nos creará un fichero con la configuración que acabamos de ver, podemos comprobarlo con:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">cat</span> mario.yaml
</code></pre></div>
<p>Ahora le indicamos a kubernetes que cree lo que dice el fichero:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl create -f mario.yaml
</code></pre></div>
<p>Nos indica que ya esta creado<br>
<img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-16-a-las-20.25.45.png" alt="Docker VIII - Kubernetes III: Introducción a los PODS"/></br></p>
<p>Aunque realmente esa es la respuesta de kubernetes al comando, realmente lo creará cuando este en la fase de <em>reconciliación</em> de su ciclo de vida y vea que algo no cuadra entre lo que tiene y lo que se supone que debe tener según nuestros comandos.</p>
<p>Si ahora ejecutamos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl get pods
</code></pre></div>
<p>Podemos ver como tenemos otro contenedor creado con el nombre que le hemos indicado</p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-16-a-las-20.28.01.png" alt="Docker VIII - Kubernetes III: Introducción a los PODS"/></p>
<p>Si por algún motivo no sabemos realmente que es lo que tiene un pod en cuestión podemos ver toda la información relevante usando el comando:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl describe pod mario-test
</code></pre></div>
<p>Con esto veremos toda la información posible:</p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-16-a-las-20.31.02.png" alt="Docker VIII - Kubernetes III: Introducción a los PODS"/></p>
<p>Como el nombre, el nodo donde se encuentra, su estadom la IP..... incluso si nos vamos al final de lo que nos ha mostrado la consola podremos ver un listado de eventos con lo que ha ido pasando con este pod</p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-16-a-las-20.32.01.png" alt="Docker VIII - Kubernetes III: Introducción a los PODS"/></p>
<p>Bueno y hasta aquí este post de introducción a los PODS, en el siguiente podremos ver algo vas información y configuraciones más avanzadas, nos vemos un abrazoooooor</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[JS Algoritmos y Estructuras de datos V: La recursividad y su pequeño problema en Javascript]]></title><description><![CDATA[Hablemos ahora de la Recursividad. A la gran mayoría por lo menos nos tiene que
sonar ¿no?... por lo menos nos habrán dicho que es muy chula, que mola usarla,
que porque no lo pruebas... pues bien he de coincidir con casi cualquier cosa
buena que se diga sobre este concepto, aunque claro lo suyo es usarlo cuando
toque y tenga sentido (pero eso es otra historia).
Por ahora veremos que es esto de la recursividad, para que nos sirve y cual es
el problema que nos generará a la larga (y como resolve]]></description><link>https://jlgarcia.fulldev.ninja/js-algorithm-and-data-structures-recursion/</link><guid isPermaLink="false">Ghost__Post__5c18a5012dd6610fd828cacd</guid><category><![CDATA[algoritmos]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 07 Dec 2020 09:33:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640-2.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640-2.png" alt="JS Algoritmos y Estructuras de datos V: La recursividad y su pequeño problema en Javascript"/><p>Hablemos ahora de la <strong>Recursividad</strong>. A la gran mayoría por lo menos nos tiene que sonar ¿no?... por lo menos nos habrán dicho que es muy chula, que mola usarla, que porque no lo pruebas... pues bien he de coincidir con casi cualquier cosa buena que se diga sobre este concepto, aunque claro lo suyo es usarlo cuando toque y tenga sentido (pero eso es otra historia).</p>
<p>Por ahora veremos que es esto de la recursividad, para que nos sirve y cual es el problema que nos generará a la larga (y como resolverlo) esto en nuestro querido <em>Javascript</em>.</p>
<h3 id="recursividad">Recursividad</h3>
<p>No me voy a extender en explicaciones técnicas en este caso (profundizaré más en el post de la línea de javascript funcional), por lo que, en palabras simples, es la capacidad de una función de llamarse a si misma. Esto es más un concepto de programación funcional, pero debido a que las funciones en javascript se pueden tratar como cualquier otro objeto (ciudadano de primera clase), es decir, que se puede pasar por parámetro, retornar dentro de otra función.... y todo lo que se nos ocurra, podemos hacer uso de la recursión también.</p>
<p>Algunos ejemplos de su uso podrian ser: Recorrer un sistema de ficheros (abrir primera carpeta, recorrer lo que hay dentro y si encuentra una carpeta la abre y recorre...y asi sucesivamente), se suele ver en la típica resolución de problemas sobre los números de <em>Fibonacci</em> (que es y ejemplos <a href="https://medium.com/developers-writing/fibonacci-sequence-algorithm-in-javascript-b253dc7e320e">aquí</a>) o en general cualquier problema que requiera repetir lógica sobre un mismo elemento (y no necesitemos o no tenga sentido funcional que usemos un bucle de los habituales)</p>
<p>Veamos cuales son los detalles de una función recursiva. Ya hemos comentado que en la teoría se supone que es una función que se llama a si misma, como por ejemplo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">addTo</span> <span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> number <span class="token operator">+</span> <span class="token function">addTo</span><span class="token punctuation">(</span>number <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
</code></pre></div>
<p>La teoría de la función sería que queremos sumar los números desde 0 hasta el número dado. Visualmente tiene sentido, ¿no?, sumamos el número que recibimos primero que sería el 10 y luego llamamos a la misma función para que use el 9 y así sucesivamente. Pero claro si nos fijamos bien aquí tenemos un problema, si ejecutaramos esto tendriamos un <strong>bucle infinito</strong> porque en ningún momento le indicamos cuando tiene que parar. Lo que le falta a esta función es lo que se conoce como <strong>caso base</strong>.</p>
<p>El <strong>caso base</strong> es la unidad mínima que debe devolver una función recursiva, si pensamos en lo que queríamos hacer que era sumar del 0 al 10, en este caso nos falta indicarle que cuando llegue a 0 nos devuelva el número, este sería nuestro caso base, <strong>siempre debe tener un caso base</strong>.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">addTo</span><span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>number <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> number
<span class="token punctuation">}</span>
<span class="token keyword">return</span> number <span class="token operator">+</span> <span class="token function">addTo</span><span class="token punctuation">(</span>number <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Si ahora ejecutamos esto todo iria bien y nos debería devolver 55. Esto es un caso muy sencillo para explicar que es la recursión pero veamos rápidamente que es lo que lo pasa por debajo.</p>
<p>Para ello lo primero es repasar que es el <strong>call stack</strong>. El <em>call stack</em> o <em>pila de llamadas</em> (lo defino a mi rollo por simplicicad) son las funciones que se tienen que ejecutar (con estructura <em>LIFO</em>) dentro de un <em>Task</em> del event loop. En el próximo post profundizaremos más en que es cada cosa y el flujo que sigue el eventloop, con lo que nos tenemos que quedar ahora mismo es que el <em>call stack</em> es el trabajo que tiene pendiente javascript para poder pasar a la siguiente tarea (es decir que nuestro thread esta bloqueado hasta que termine).</p>
<p>Para verlo bien vamos a usar una herramienta que me he encontrado (grandisima ayuda para entender esto visualmente ya lo veremos, agradecer a los creadores) que es <a href="https://www.jsv9000.app/">jsv9000</a>. Esta herramienta nos permite comprobar visualmente lo que pasa dentro de nuestro eventloop en cada una de sus Queues.</p>
<p>Lo que haremos será añadir el código siguiente y darle a <strong>run</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">addTo</span><span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>number <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> number
<span class="token punctuation">}</span>
<span class="token keyword">return</span> number <span class="token operator">+</span> <span class="token function">addTo</span><span class="token punctuation">(</span>number <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">finish</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Finished'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>
<span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Lo que hace la herramienta es indicarnos en que puesto está nuestro código y que ha ido pasando por dentro paso a paso, por lo que tenemos que ir dandole a <strong>step</strong>. Si le damos 6 veces (como le hemos indicado que hasta 5 y empezamos en el 0) vemos como el código lo único que ha hecho es incluir 6 llamadas en el call stack de la función de suma en la fase de <em>evaluación</em></p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-21-a-las-14.05.32.png" alt="JS Algoritmos y Estructuras de datos V: La recursividad y su pequeño problema en Javascript"/></p>
<p>Si le continuamos dando a <strong>step</strong> vemos como se va vaciando el call stack de la función y lo siguiente es el método <em>finish</em> que nos muestra el resultado del <em>console.log</em>. En este caso lo que vemos es que nuestra función recursiva va acumulando llamadas en el call stack hasta que llega al caso base y empieza a devolver datos y a vaciar. Si lo queremos ver más claro añadimos unos logs</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">addTo</span><span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>number <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> number
<span class="token punctuation">}</span>
<span class="token keyword">const</span> result <span class="token operator">=</span> number <span class="token operator">+</span> <span class="token function">addTo</span><span class="token punctuation">(</span>number <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'result: '</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span>
<span class="token keyword">return</span> result
<span class="token punctuation">}</span>
<span class="token keyword">function</span> <span class="token function">finish</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Finished'</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token function">addTo</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>
<span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Y podemos ver en acción realmente donde estamos</p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-21-a-las-14.19.09.png" alt="JS Algoritmos y Estructuras de datos V: La recursividad y su pequeño problema en Javascript"/></p>
<p>Una vez entendido esto, ahora os planteo el gran problema que resolveremos en próximos posts. Cambiemos el código por lo siguiente pero no recomiendo ejecutarlo en la herramienta que tardaría muchisimo, ejecutarlo en la consola del navegador, en un fichero de node o donde más os guste</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">addTo</span><span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>number <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> number
<span class="token punctuation">}</span>
<span class="token keyword">return</span> number <span class="token operator">+</span> <span class="token function">addTo</span><span class="token punctuation">(</span>number <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">addTo</span><span class="token punctuation">(</span><span class="token number">100000</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Fijaos el número que he puesto <strong>100000</strong>, esto nos debe dar un error como el siguiente:</p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-21-a-las-14.23.21.png" alt="JS Algoritmos y Estructuras de datos V: La recursividad y su pequeño problema en Javascript"/></p>
<p>Es decir hemos llegado al límite de acciones posibles dentro de la pila de llamadas, si nos planteamos lo que ocurria con 5, que teniamos 6 inclusiones el call stack, ahora tendríamos 100001 (se que este número es muy grande pero depende de lo que estemos haciendo o donde puede ser mucho menos, realmente insisto en que es un error muy habitual). Este problema viene dado porque javascript no es un lenguaje orientado a este tipo de funciones, pero siempre podemos encontrarle solución, en los próximos post veremos como podemos solucionar esto de muchas maneras, mientras tando plantear vosotros posibles soluciones. Nos vemos en el siguiente un abrazoooooor</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker VII - Kubernetes II: Lanzando nuestra primera imagen]]></title><description><![CDATA[En este punto vamos a ver lo primero como seria lanzar o desplegar una
aplicación usando kubernetes, para ello vamos a usar una imagen de docker
pública (agradecer a los creadores, el contenido de esa imagen no tiene nada que
ver conmigo) que contiene una versión de un juego de nuestro querido fontanero
MARIO (Mas info [https://hub.docker.com/r/pengbai/docker-supermario/]). Para
lanzarla lo que hacemos es:
kubectl run mario-test --image=pengbai/docker-supermario:latest --port=8080
En este com]]></description><link>https://jlgarcia.fulldev.ninja/docker-vi-kubernetes-ii-nuestra-primera-app-en-kubernetes/</link><guid isPermaLink="false">Ghost__Post__5fafd4b8a6c0f5058bff45a0</guid><category><![CDATA[Docker]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 30 Nov 2020 09:33:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice-1.jpg" alt="Docker VII - Kubernetes II: Lanzando nuestra primera imagen"/><p>En este punto vamos a ver lo primero como seria lanzar o desplegar una aplicación usando kubernetes, para ello vamos a usar una imagen de docker pública (agradecer a los creadores, el contenido de esa imagen no tiene nada que ver conmigo) que contiene una versión de un juego de nuestro querido <strong>fontanero MARIO</strong> (Mas <a href="https://hub.docker.com/r/pengbai/docker-supermario/">info</a>). Para lanzarla lo que hacemos es:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl run mario-test --image<span class="token operator">=</span>pengbai/docker-supermario:latest --port<span class="token operator">=</span><span class="token number">8080</span>
</code></pre></div>
<p>En este comando lo que hacemos es indicarle a kubernetes que queremos arrancar un contenedor o un servicio con nombre <em>mario-test</em> con la imagen en cuestión que vemos en dockerhub y que esta aplicación escucha en el <strong>puerto 8080</strong> (esto depende de cada imagen, en nuestro caso es ese, mirar la información de cada imagen para saber cual es el puerto que realmente escucha).<br>
Al ejecutarse lo que hace es descargarse la imagen de docker hub y arrancarla.</br></p>
<p>Si todo va bien la respuesta seria algo similar a esto:<br>
<img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-14-a-las-14.08.34.png" alt="Docker VII - Kubernetes II: Lanzando nuestra primera imagen"/></br></p>
<p>Podemos ver el estado de este contenedor con:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl get pods
</code></pre></div>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-14-a-las-14.12.40.png" alt="Docker VII - Kubernetes II: Lanzando nuestra primera imagen"/></p>
<p>Por el momento no nos preocuparemos con que significa cada comando, lo que queremos hacer es comprobar como es empezar a trabajar con kubernetes.<br>
Como vemos en la imagen tenemos un algo llamado pod con el nombre <strong>mario-test</strong>, este nombre es necesario para poder realmente acceder a nuestro contenedor.<br>
En el comando que hemos lanzado para instanciar la imagen en cuestión, le hemos indicado el puerto por el que trabaja realmente el contenedor pero como tal nosotros no tenemos acceso a ese puerto, debemos hacer lo que se conoce como un <em>port-forwarding</em> para <em>sincronizar</em> un puerto de nuestra máquina con el puerto del contenedor, para ello ejecutaremos lo siguiente:</br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl port-forward mario-test <span class="token number">8000</span>:8080
</code></pre></div>
<p>Aqui lo que le indicamos es que sincronice nuestro puerto 8000 con el 8080 del contenedor o aplicación con el nombre <em>mario-test</em>. Si todo va bien veremos algo como:</p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-14-a-las-14.19.53.png" alt="Docker VII - Kubernetes II: Lanzando nuestra primera imagen"/></p>
<p>Y si ahora nos vamos a nuestro navegador e intentamos acceder a <strong>localhost:8000</strong>, nos debería aparecer nuestro juego</p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-14-a-las-14.14.53.png" alt="Docker VII - Kubernetes II: Lanzando nuestra primera imagen"/></p>
<p>Ojo tenemos que tener en cuenta que el comando de port-forward se queda ejecutandose hasta que lo paremos</p>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-14-a-las-14.23.55.png" alt="Docker VII - Kubernetes II: Lanzando nuestra primera imagen"/></p>
<p>Si nosotros paramos el comando en cuestión veremos como ya no podemos acceder a nuestra página con el juego de mario.</p>
<p>Este post ha sido solo un post introductorio para que veamos como seria desplegar una imagen básica usando kubernetes. En los próximos post entraremos más en detalle en como funciona todo esto y haremos muchas más cosas viendo todas las capacidades de kubernetes, un abrazooooo nos vemos en el siguiente.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[JS Algoritmos y estructuras de datos IV: Resolución de problemas-> Patrón Sliding Window]]></title><description><![CDATA[Este patrón como su nombre indica se basa en "mover una ventana", es decir,
tratamos con los datos que estan dentro de esa ventana ignorando el resto, y
vamos deslizando la ventana con los siguientes datos.
Veamoslo con un ejemplo. Dentro de un array queremos obtener la suma mayor entre
"n" de esos números consecutivos, es decir, si por ejemplo queremos saber cual
es la suma mayor de 2 números consecutivos de este array:
[1,4,2,6,3,9]
Tendremos que sumar:
* 1 + 4
* 4 + 2
* 2 + 6
* 6 + 3
]]></description><link>https://jlgarcia.fulldev.ninja/js-algoritmos-y-estructuras-de-datos-iii-patron-sliding-window/</link><guid isPermaLink="false">Ghost__Post__5fa84de4a6c0f5058bff43db</guid><category><![CDATA[algoritmos]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 24 Nov 2020 09:03:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640-1.png" alt="JS Algoritmos y estructuras de datos IV: Resolución de problemas-> Patrón Sliding Window"/><p>Este patrón como su nombre indica se basa en "<em>mover una ventana</em>", es decir, tratamos con los datos que estan dentro de esa ventana ignorando el resto, y vamos deslizando la ventana con los siguientes datos.<br>
Veamoslo con un ejemplo. Dentro de un array queremos obtener la suma mayor entre "n" de esos números consecutivos, es decir, si por ejemplo queremos saber cual es la suma mayor de 2 números consecutivos de este array:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">9</span><span class="token punctuation">]</span>
</code></pre></div>
<p>Tendremos que sumar:</p>
<ul>
<li>1 + 4</li>
<li>4 + 2</li>
<li>2 + 6</li>
<li>6 + 3</li>
<li>3 + 9</li>
</ul>
<p>Por eso he comentado que es como mover una ventana o una caja donde solo entran 2 números y sumamos cada vez que cambia uno de los números.</p>
<p>Veamos el posible acercamiento mas habitual o sencillo (el que solemos hacer primero) aunque sería el más lento</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// arr: el array a comprobar</span>
<span class="token comment">// num: número de elementos en el subarray, de cuantos números queremos realizar el cálculo</span>
<span class="token keyword">function</span> <span class="token function">maxSubarraySum</span> <span class="token punctuation">(</span><span class="token parameter">arr<span class="token punctuation">,</span> num</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>num <span class="token operator">></span> arr<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> max <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">Infinity</span><span class="token punctuation">;</span>
<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length <span class="token operator">-</span> num <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
temp <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator"><</span> num<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
temp <span class="token operator">+=</span> arr<span class="token punctuation">[</span>i<span class="token operator">+</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>temp <span class="token operator">></span> max<span class="token punctuation">)</span> <span class="token punctuation">{</span>
max <span class="token operator">=</span> temp<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> max<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Como vemos tenemos un "nested loop", y lo que hacemos es recorrer cada número en el primer loop y en el segundo sumamos los "n" números siguientes.</p>
<p>Es relativamente fácil pero tenemos una complejidad temporal de <strong>O(n^2)</strong></p>
<p>Ahora veamos como sería usando el <strong>Sliding Pattern</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">maxSubarraySum</span> <span class="token punctuation">(</span><span class="token parameter">arr<span class="token punctuation">,</span> num</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">let</span> maxSum <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> tempSum <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>arr<span class="token punctuation">.</span>length <span class="token operator"><</span> num<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> num<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
maxSum <span class="token operator">+=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
tempSum <span class="token operator">=</span> maxSum<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> num<span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">const</span> leftLeg <span class="token operator">=</span> arr<span class="token punctuation">[</span>i <span class="token operator">-</span> num<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> rightLeg <span class="token operator">=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
tempSum <span class="token operator">=</span> tempSum <span class="token operator">-</span> leftLeg <span class="token operator">+</span> rigthLeg<span class="token punctuation">;</span>
maxSum <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>tempSum<span class="token punctuation">,</span> maxSum<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> maxSum<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Esto ya tiene algo más de <em>"chicha"</em>, así que vayamos por partes</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> num<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
maxSum <span class="token operator">+=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
tempSum <span class="token operator">=</span> maxSum<span class="token punctuation">;</span>
</code></pre></div>
<p>Sumamos los números que estarían inicialmente en la <em>ventana</em>, es decir desde "n" hasta 0 y lo establecemos en una variable que usaremos de comodín para ir moviéndonos (<em>tempSum</em>)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> num<span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">const</span> leftLeg <span class="token operator">=</span> arr<span class="token punctuation">[</span>i <span class="token operator">-</span> num<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> rightLeg <span class="token operator">=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
tempSum <span class="token operator">=</span> tempSum <span class="token operator">-</span> leftLeg <span class="token operator">+</span> rigthLeg<span class="token punctuation">;</span>
maxSum <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>tempSum<span class="token punctuation">,</span> maxSum<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>A continuación recorremos empezando por "n", es decir, después de sumar los "n" primeros números, y el paso sería elimino el primero y añado el siguiente, (para clarificar con el ejemplo de la ventana he creado <em>leftLeg</em> como limite o pata izquierda de la ventana y <em>rightLeg</em> como el derecho ) siendo más específico lo que hacemos es restarle a <em>tempSum</em> el primer número dentro de nuestra "ventana o cajón", que seria <em>leftLeg</em> y le añadimos el siguiente que esté fuera, es decir <em>rightLef</em>. Y vamos comparando con el valor anterior y metiendo el mayor dentro de la variable <strong>maxTemp</strong></p>
<p>Siguiendo con el ejemplo de antes con este array, usando 2 valores consecutivos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">9</span><span class="token punctuation">]</span>
</code></pre></div>
<p>Los pasos serían:</p>
<ul>
<li>En el primer loop, se suman los 2 primeros, con un resultado de 5 y se asigna a la variable tempSum.</li>
<li>En el segundo loop se le resta a tempSum el 1, se le suma 2, lo que nos daría 6 y así sucesivamente</li>
<li>6 - 4 + 6</li>
<li>8 - 2 + 3</li>
<li>9 - 6 + 9</li>
<li>Lo que nos daría 12</li>
</ul>
<h4 id="otroejemploalgomscomplicado">Otro ejemplo algo más complicado.</h4>
<p>En este caso la idea es encontrar el mínimo número de elementos necesarios del array que su suma sea igual o superior al número dado. Veamoslo con números primero, tenemos este array:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">6</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span>
</code></pre></div>
<p>Y queremos saber cual es la menor cantidad de números de ese array que su suma sea igual o mayor que <strong>9</strong>. En este caso serian necesarios 2 números (5+4).</p>
<p>Antes de ver el ejemplo, os cuento lo que haremos:</p>
<ol>
<li>En este caso empezaremos a sumar desde 0, creando nosotros la ventana, hasta que la suma sea mayor o igual que el número que buscamos.</li>
<li>Cuando la suma sea mayor o igual veremos cuantos números hemos necesitado, lo apuntaremos y empezaremos a mover la ventana (recordar restando el primer número y sumando el siguiente)</li>
</ol>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">minSubArrayLen</span><span class="token punctuation">(</span><span class="token parameter">nums<span class="token punctuation">,</span> sum</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">let</span> total <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> start<span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> end <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> minLen <span class="token operator">=</span> <span class="token number">Infinity</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>start <span class="token operator"><</span> nums<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">//Si la ventana actual no es mayor o igual que el número dado movemos la ventana a la derecha, es decir ampliamos la ventana</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>total <span class="token operator"><</span> sum <span class="token operator">&&</span> end <span class="token operator"><</span> nums<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">{</span>
total <span class="token operator">+=</span> nums<span class="token punctuation">[</span>end<span class="token punctuation">]</span><span class="token punctuation">;</span>
end<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//Si la ventana actual suma al menos la suma dada entonces podemos reducir la ventana</span>
<span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>total <span class="token operator">>=</span> sum<span class="token punctuation">)</span><span class="token punctuation">{</span>
minLen <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span>minLen<span class="token punctuation">,</span> end <span class="token operator">-</span> start<span class="token punctuation">)</span><span class="token punctuation">;</span>
total <span class="token operator">-=</span> nums<span class="token punctuation">[</span>start<span class="token punctuation">]</span><span class="token punctuation">;</span>
start<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token comment">//Si el total actual es menor que lo que necesitamos pero hemos llegado al final, necesitamos el break para no un infinite loop</span>
<span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> minLen <span class="token operator">===</span> <span class="token number">Infinity</span> <span class="token operator">?</span> <span class="token number">0</span> <span class="token operator">:</span> minLen<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<h4 id="otroejemploms">Otro ejemplo más</h4>
<p>En este caso queremos contar los carácteres del substring mas largo con carácteres distintos, es decir, buscamos un substring sin que se repita ninguna letra. Aquí usaremos una mezcla entre el <strong>frequency counter y el sliding pattern</strong>. Básicamente iremos anotando las letras por las que pasamos e ir moviendo la window según se repitan</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">findLongestSubstring</span><span class="token punctuation">(</span><span class="token parameter">str</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> longest <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> seen <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> start <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> str<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> char <span class="token operator">=</span> str<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token comment">//Comprobamos si ya lo tenemos, y si existe, nuestro start seria el que tenemos anotado ya</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>seen<span class="token punctuation">[</span>char<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
start <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>start<span class="token punctuation">,</span> seen<span class="token punctuation">[</span>char<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Sumamos uno para tener en cuenta el caracter actual</span>
longest <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>longest<span class="token punctuation">,</span> i <span class="token operator">-</span> start <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// guardamos el índice con el siguiente carácter si se repite no contarlo, el nuevo esta dentro</span>
<span class="token comment">// de la ventana</span>
seen<span class="token punctuation">[</span>char<span class="token punctuation">]</span> <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> longest<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Este ejemplo es algo más díficil de entender, creo que sobretodo el moviento de la ventana, por explicarlo un poco más supongamos que queremos saber la cantidad de caracteres máximo consecutivo donde no se repite ningún caracter de la palabra <em>ninja</em> (como no...), el resultado sería 4 pero veamos un poco el flujo hasta que cambia (tengamos en cuenta que <em>i</em> y <em>start</em> son las "patas" de la ventana):</p>
<ul>
<li>Empieza siendo <em>i</em> 0 por lo que empezamos con la <em>n</em>, como no tenemos nada guardado todavía dentro de <em>seen</em> la variable <em>start</em> se queda con 0, <em>longest</em> sería 1 (tanto i como start son 0) y se guardaría <em>seen.n = 1</em></li>
<li>A continuación la <em>i</em> del index es 1, lo que hace que la siguiente letra sea la <em>i</em>. No existe todavía dentro de <em>seen</em> por lo que <em>start</em> todavía seguiría siendo 0, <em>longest</em> pasaría a ser 2 (<em>i</em> es 1 y <em>start</em> 0) y guardamos <em>seen.i = 2</em></li>
<li>En la siguiente iteración la <em>i</em> del index es 2, por lo que la siguiente letra es <em>n</em>. En este caso si que tenemos coincidencia dentro <em>seen</em> por lo que <em>start</em> pasaría a ser 1. Aquí es donde está la parte algo más complicada de ver al principio, este paso es el porqué de guardar cada letra con un +1 dentro de <em>seen</em>. Para explicarlo pensemos en el concepto de la ventana, antes de pasar por la modificación del <em>start</em> tenemos que el borde izquierdo (la posición actual del <em>start</em>) esta en la posición 0 y el borde derecho (la <em>i</em>) está en la posición 2, al encontrar coincidencía lo que tenemos que hacer es mover la posición del borde izquierdo para sacar la <em>n</em> de nuestro rango de la ventana por lo que para sacarla sería mover la posición actual del borde izquierdo a <em>n</em> + 1, es decir, movernos al siguiente carácter. Nuestra ventana ahora pasa de estar en <em>nin</em> a <em>in</em>. Hemos movido el <em>start</em> de 0 a 1 por lo que en este caso si la <em>i</em> es 2 entonces <em>longest</em> sigue siendo 2 y ahora como ya existe la <em>n</em> dentro <em>seen</em> pasamos a tener <em>seen.n = 3</em></li>
<li>Ahora la <em>i</em> del index es 3, por lo que la siguiente letra es <em>j</em>, como no hemos pasado por ninguna nuestro <em>start</em> no cambia sigue en 1, <em>longest</em> ahora pasaría a ser 3 (<em>i</em> es 3, <em>start</em> es 1) y guardariamos <em>seen.j = 4</em></li>
<li>Por último la <em>i</em> del index es 4, por lo que ya estariamos en la última letra que es la <em>a</em>, como no tenemos ninguna <em>start</em> sigue siendo 1, <em>longest</em> ahora pasaría a ser 4 (<em>i</em> es 4 y <em>start</em> es 1) y por último se guardaría <em>seen.a = 5</em></li>
</ul>
<p>En este punto terminaría la ejecución y nos devolvería <em>longest</em> que sería 4, es decir, <em>inja</em>. En este ejemplo lo más importante es ver como se mueve la ventana realmente, que lo que hace es ir creciendo hasta que encuentra una repetición y coloca su <em>start</em> a continuación de la repetición para comenzar de nuevo sin incluir ese carácter.</p>
<p>Creo que más o menos con estos ejemplos se entiende cual es el funcionamiento de este patrón de resolución de problemas que puede ser bastante útil si queremos sacar y comparar información entre elementos dentro de un mismo array.</p>
<p>Y hasta aquí este post nos vemos en el siguienteeeee, un abrazooooor</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Javascript Funcional III: Composición de funciones]]></title><description><![CDATA[Bien vamos con la última de las características que tiene la programación
funcional antes de adentrarnos puramente en propiedades funcionales. En este
caso vamos a ver en detalle que es eso de Composición de funciones.
Esto realmente no tiene mucha ciencia, el propio nombre nos indica de que va, se
trata de aplicar funciones en cadena para lógicas más complejas. Esto se suele
ver en ciertas librerias como composition, pipe, flow..., primero veremos como
aplicar esto de forma nativa y ya veremos]]></description><link>https://jlgarcia.fulldev.ninja/javascript-funcional-iii-composicion-de-funciones/</link><guid isPermaLink="false">Ghost__Post__5fa7e206a6c0f5058bff43c9</guid><category><![CDATA[funcional]]></category><category><![CDATA[javascript]]></category><category><![CDATA[ramda]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Fri, 20 Nov 2020 10:37:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/28e76839a7fb382fbbe244b857f2980c/Capture-5-1-1.jpeg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/28e76839a7fb382fbbe244b857f2980c/Capture-5-1-1.jpeg" alt="Javascript Funcional III: Composición de funciones"/><p>Bien vamos con la última de las características que tiene la programación funcional antes de adentrarnos puramente en propiedades funcionales. En este caso vamos a ver en detalle que es eso de <em>Composición de funciones</em>.</p>
<p>Esto realmente no tiene mucha ciencia, el propio nombre nos indica de que va, se trata de aplicar funciones en cadena para lógicas más complejas. Esto se suele ver en ciertas librerias como <em>composition, pipe, flow...</em>, primero veremos como aplicar esto de forma nativa y ya veremos algún atajo con alguna libreria.</p>
<p>Continuemos con la teoria de uno de los ejemplos anteriores que es la de crear un <em>player</em> inicial para un juego:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">setName</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter">player</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
player<span class="token punctuation">.</span>name <span class="token operator">=</span> name
<span class="token keyword">return</span> player
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">setPowers</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">player</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> availablePowers <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'fly'</span><span class="token punctuation">,</span> <span class="token string">'invisibility'</span><span class="token punctuation">,</span> <span class="token string">'bulletproof'</span><span class="token punctuation">,</span> <span class="token string">'superstrength'</span><span class="token punctuation">]</span>
player<span class="token punctuation">.</span>powers <span class="token operator">=</span> availablePowers<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> availablePowers<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">return</span> player
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">setWeapon</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">player</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> availableWeapons <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'gun'</span><span class="token punctuation">,</span> <span class="token string">'katana'</span><span class="token punctuation">,</span> <span class="token string">'ninja star'</span><span class="token punctuation">,</span> <span class="token string">'grenade'</span><span class="token punctuation">]</span>
player<span class="token punctuation">.</span>weapon <span class="token operator">=</span> availableWeapons<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> availableWeapons<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">return</span> player
<span class="token punctuation">}</span>
<span class="token keyword">const</span> newPlayer <span class="token operator">=</span> <span class="token function">setWeapon</span><span class="token punctuation">(</span><span class="token function">setPowers</span><span class="token punctuation">(</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">'Ninja'</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>newPlayer<span class="token punctuation">)</span>
</code></pre></div>
<p>Si nos fijamos en el contenido de <em>newPlayer</em>, es donde tenemos nuestra composición de funciones, lo que se suele ver como:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token function">f</span><span class="token punctuation">(</span><span class="token function">g</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>En este caso puede que sea facil de entender lo que estamos haciendo en este caso, pero si tuvieramos esta forma en soluciones más complejas puede que no nos enteremos de nada, por lo que veamos como ir mejorando nuestra teoria de la composición.</p>
<p>Lo primero que haremos será crear nuestro propio método <em>compose</em>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">compose</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>fns</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token parameter">x</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> fns<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">previous<span class="token punctuation">,</span> current</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">current</span><span class="token punctuation">(</span>previous<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> x<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Este método compose lo que hace es recibir una cantidad <strong>n</strong> de funciones que debe aplicar sobre un valor inicial <strong>x</strong>. En este caso lo hace de <strong>izquierda a derecha</strong>, muchas veces se usa <strong>reduceRight</strong> para hacerlo de <strong>derecha a izquierda</strong>, depende de cuales sean los métodos a usar para la composición nos interesa más una dirección u otra (por defecto derecha a izquierda aunque a mí me gusta más izquierda a derecha).</p>
<p>Ahora con esta función compose solo tenemos que usarla:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">compose</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>fns</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token parameter">x</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> fns<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">previous<span class="token punctuation">,</span> current</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">current</span><span class="token punctuation">(</span>previous<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> x<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">setName</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter">player</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
player<span class="token punctuation">.</span>name <span class="token operator">=</span> name
<span class="token keyword">return</span> player
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">setPowers</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">player</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> availablePowers <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'fly'</span><span class="token punctuation">,</span> <span class="token string">'invisibility'</span><span class="token punctuation">,</span> <span class="token string">'bulletproof'</span><span class="token punctuation">,</span> <span class="token string">'superstrength'</span><span class="token punctuation">]</span>
player<span class="token punctuation">.</span>powers <span class="token operator">=</span> availablePowers<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> availablePowers<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">return</span> player
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">setWeapon</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">player</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> availableWeapons <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'gun'</span><span class="token punctuation">,</span> <span class="token string">'katana'</span><span class="token punctuation">,</span> <span class="token string">'ninja star'</span><span class="token punctuation">,</span> <span class="token string">'grenade'</span><span class="token punctuation">]</span>
player<span class="token punctuation">.</span>weapon <span class="token operator">=</span> availableWeapons<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> availableWeapons<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">return</span> player
<span class="token punctuation">}</span>
<span class="token keyword">const</span> newPlayer <span class="token operator">=</span> <span class="token function">setWeapon</span><span class="token punctuation">(</span><span class="token function">setPowers</span><span class="token punctuation">(</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">'Ninja'</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> otherPlayer <span class="token operator">=</span> <span class="token function">compose</span><span class="token punctuation">(</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">'Ninja'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> setPowers<span class="token punctuation">,</span> setWeapon<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>newPlayer<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>otherPlayer<span class="token punctuation">)</span>
</code></pre></div>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-08-a-las-14.50.00.png" alt="Javascript Funcional III: Composición de funciones"/></p>
<p>Como podemos ver ambas funcionan correctamente y es un poco más sencillo de entender lo que estamos haciendo. Recuerdo que este ejemplo es un poco forzado es solo orientativo para ver la funcionalidad <em>compose</em>.</p>
<p>Veamos el ejemplo con <strong>Ramda</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token constant">R</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'ramda'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> <span class="token function-variable function">setName</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter">player</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
player<span class="token punctuation">.</span>name <span class="token operator">=</span> name
<span class="token keyword">return</span> player
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">setPowers</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">player</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> availablePowers <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'fly'</span><span class="token punctuation">,</span> <span class="token string">'invisibility'</span><span class="token punctuation">,</span> <span class="token string">'bulletproof'</span><span class="token punctuation">,</span> <span class="token string">'superstrength'</span><span class="token punctuation">]</span>
player<span class="token punctuation">.</span>powers <span class="token operator">=</span> availablePowers<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> availablePowers<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">return</span> player
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">setWeapon</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">player</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> availableWeapons <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'gun'</span><span class="token punctuation">,</span> <span class="token string">'katana'</span><span class="token punctuation">,</span> <span class="token string">'ninja star'</span><span class="token punctuation">,</span> <span class="token string">'grenade'</span><span class="token punctuation">]</span>
player<span class="token punctuation">.</span>weapon <span class="token operator">=</span> availableWeapons<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> availableWeapons<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">return</span> player
<span class="token punctuation">}</span>
<span class="token keyword">const</span> newPlayer <span class="token operator">=</span> <span class="token function">setWeapon</span><span class="token punctuation">(</span><span class="token function">setPowers</span><span class="token punctuation">(</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">'Ninja'</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">// Aquí en lugar de compose usamos el método en cuestión de R que es pipe</span>
<span class="token keyword">const</span> otherPlayer <span class="token operator">=</span> <span class="token constant">R</span><span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">setName</span><span class="token punctuation">(</span><span class="token string">'Ninja'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> setPowers<span class="token punctuation">,</span> setWeapon<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>newPlayer<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>otherPlayer<span class="token punctuation">)</span>
</code></pre></div>
<p>Solo tenemos que usar <strong>pipe</strong> para hacerlo de izquierda a derecha o <strong>compose</strong> para hacerlo de derecha a izquierda</p>
<p>Un detalle importante a tener en cuenta y que hacemos uso en el ejemplo, es lo que se conoce como <em>programación tacita o point free</em>, este concepto se refiere a la omisión de los parámetros de los métodos cuando lo usamos por ejemplo en una composición como esta que hemos visto, debido a que los valores de retorno de unos métodos son los de entrada de otros por lo que como el proceso se realiza automáticamente lo podemos omitir. En este caso que hemos visto siempre se retorna el mismo objeto, pero pudiera ser cualquier otro caso mientras que se cumpla este concepto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript">funcA <span class="token operator">:</span><span class="token operator">:</span> <span class="token constant">A</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token constant">B</span>
funcB <span class="token operator">:</span><span class="token operator">:</span> <span class="token constant">B</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token constant">C</span>
<span class="token comment">// Esto lo podemos encadenar porque funcB espera como valor de entrada B que es lo que devuelve funcA</span>
funcC<span class="token operator">:</span><span class="token operator">:</span> funcA <span class="token operator">+</span> funcB <span class="token operator">:</span><span class="token operator">:</span> <span class="token constant">A</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token constant">B</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token constant">C</span>
</code></pre></div>
<p>Creo que con esto se entiende más o menos lo básico sobre la composición, en los próximos capítulos veremos elementos más puramente funcionales como pueden ser los <strong>Funtores</strong>, una abrazooooo</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker VI - Kubernetes I: Intro e instalación]]></title><description><![CDATA[En general ya tenemos una idea de que es Kubernetes, seguro que lo hemos oido o
leido en algún momento, en un resumen muy escueto, podemos decir que es una
herramienta de instrumentación/orquestación de nodos de Docker, estos pueden
estar en uno o varios servidores. Nos provee de una serie de herramientas para
poder gestionar nuestros conjuntos de aplicaciones que están funcionando en
varios contenedores Docker.
Instalación
En un primer momento comentar que realmente Kubertenes es un servicio q]]></description><link>https://jlgarcia.fulldev.ninja/kubernetes-i-intro-e-instalacion/</link><guid isPermaLink="false">Ghost__Post__5fafcc29a6c0f5058bff4598</guid><category><![CDATA[Docker]]></category><category><![CDATA[kubernetes]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 17 Nov 2020 10:03:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8f47faaada0e810968ad97255d3f8852/learning-docker-and-k8s-by-practice.jpg" alt="Docker VI - Kubernetes I: Intro e instalación"/><p>En general ya tenemos una idea de que es Kubernetes, seguro que lo hemos oido o leido en algún momento, en un resumen muy escueto, podemos decir que es una herramienta de instrumentación/orquestación de nodos de Docker, estos pueden estar en uno o varios servidores. Nos provee de una serie de herramientas para poder gestionar nuestros conjuntos de aplicaciones que están funcionando en varios contenedores Docker.</p>
<h1 id="instalacin">Instalación</h1>
<p>En un primer momento comentar que realmente Kubertenes es un servicio que estará funcionando en algún proveedor cloud (AWS/Gooogle/Azure...), por lo que propiamente dicho no tendriamos una instalación. En esta sección veremos como instalar un entorno local de pruebas de kubernetes y las herramientas habituales de gestión de kubernetes (que estas si que se usan en producción)</p>
<h3 id="clidegestinkubernetes">CLI de gestión kubernetes</h3>
<p>El servicio de Kubernetes como tal, dispone de una API para su gestión, es decir, que podríamos usar postman o curl para gestionar nuestro entorno de kubernetes, pero esto en mi opinión para el uso habitual de kubernetes no es necesario. Disponemos de un cli específico llamado <strong>kubectl</strong> que nos proporciona todo lo necesario para la gestión de cualquier entorno de kubernetes. (Mas <a href="https://kubernetes.io/es/docs/tasks/tools/install-kubectl/#instalar-kubectl">info</a>)</p>
<p>Basicamente para su instalación en MacOs por ejemplo solo necesitamos hacer:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">brew <span class="token function">install</span> kubernetes-cli
</code></pre></div>
<p>Con esto se instalaria el cli que usaremos para trabajar.</p>
<h3 id="kubernetesenlocal">Kubernetes en local</h3>
<p>A continuación lo que haremos será instalar el servicio local que será nuestro kubernetes, para ello han creado una herramienta llamada <strong>minikube</strong> que hará las veces de server de kunernetes (Mas <a href="https://kubernetes.io/es/docs/tasks/tools/install-minikube/">info</a>).</p>
<p>Para instalarlo solo tenemos que ejecutar</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">brew <span class="token function">install</span> minikube
</code></pre></div>
<p>Esto instalará lo necesario para que minikube funcione.<br>
A continuación lo que haremos será arrancar <strong>minikube</strong> para que funcione con kubectl. Para ello es suficiente con ejecutar:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">minikube start
</code></pre></div>
<p>Esto iniciará y configurará el entorno de minikube y además hará que funcione con <strong>kubectl</strong>.<br>
Podemos indicarle también la cantidad de memoria que queremos que use por defecto nuestro servicio de minikube pasandole:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">minikube start --memory<span class="token operator">=</span><span class="token number">4096</span>
</code></pre></div>
<p>Esto haría que use 4Gb por defecto usa 2. Tiene más opciones como indicarle cantidad de CPU y demás. Si queréis ver más opciones lo ideal es mirar la documentación para verlas todas.</p>
<h3 id="probandoquetodohaidobien">Probando que todo ha ido bien</h3>
<p>Ahora ya tenemos lo básico para empezar a trabajar. Podemos comprobarlo ejecutando los comandos:</p>
<ul>
<li>Ver la versión que tenemos tanto del cliente (lo que seria kubectl) como del servidor (en este caso minikube)</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl version
</code></pre></div>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-14-a-las-13.45.00.png" alt="Docker VI - Kubernetes I: Intro e instalación"/></p>
<ul>
<li>Ver los nodos que tenemos de kubernetes (donde podemos ver el rol que tiene cada uno, en este caso MASTER)</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl get nodes
</code></pre></div>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-14-a-las-13.45.07.png" alt="Docker VI - Kubernetes I: Intro e instalación"/></p>
<ul>
<li>Ver el estado kubernetes</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">minikube status
</code></pre></div>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-14-a-las-13.48.02.png" alt="Docker VI - Kubernetes I: Intro e instalación"/></p>
<ul>
<li>Información sobre el cluster de kubernetes</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">kubectl cluster-info
</code></pre></div>
<p><img srcset="/assets/images/2020/11/Captura-de-pantalla-2020-11-14-a-las-13.49.21.png" alt="Docker VI - Kubernetes I: Intro e instalación"/></p>
<p>Con esto ya tendríamos lo básico para empezar a trabajar con kubernetes como si de un entorno de producción se tratara. En el próximo post empezaremos a mandarle instrucciones para ver como responde, un abrazoooooo</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Javascript Funcional II: Funciones puras, currying y aplicación parcial]]></title><description><![CDATA[Continuemos con nuestra serie de programación funcional, y en este caso
seguiremos hablando de sus caracteristicas con Javascript.
En el post anterior hablamos de Inmutabilidad, una característica donde no se
mutaban o modificaban los objetos si no que creabamos otros con los cambios
aplicados.
Esto es básico por ejemplo para el caso de lo siguiente que queremos hablar que
es Funciones puras
Funciones puras
Las funciones puras son aquellas donde los cambios que queramos hacer solo se
producen ]]></description><link>https://jlgarcia.fulldev.ninja/javascript-funcional-ii/</link><guid isPermaLink="false">Ghost__Post__5fa6a809a6c0f5058bff43b6</guid><category><![CDATA[funcional]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Fri, 13 Nov 2020 10:21:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/28e76839a7fb382fbbe244b857f2980c/Capture-5-1.jpeg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/28e76839a7fb382fbbe244b857f2980c/Capture-5-1.jpeg" alt="Javascript Funcional II: Funciones puras, currying y aplicación parcial"/><p>Continuemos con nuestra serie de programación funcional, y en este caso seguiremos hablando de sus caracteristicas con Javascript.<br>
En el post anterior hablamos de <strong>Inmutabilidad</strong>, una característica donde no se mutaban o modificaban los objetos si no que creabamos otros con los cambios aplicados.</br></p>
<p>Esto es básico por ejemplo para el caso de lo siguiente que queremos hablar que es <strong>Funciones puras</strong></p>
<h2 id="funcionespuras">Funciones puras</h2>
<p>Las funciones puras son aquellas donde los cambios que queramos hacer solo se producen dentro del <em>scope</em> de la función (en su interior básicamente), en ningún caso modifican variables externas. Si tenemos una función que no devuelve nada, que usa <em>this</em> o que no tiene argumentos podemos empezar a sospechar que no es pura. OJO aunque digamos que debemos cumplir este punto en la programación funcional muchas veces no es posible por ejemplo en funciones de IO donde por ejemplo trabajamos con bases de datos, pero en general debemos poder cumplir con este principio.<br>
Veamos un ejemplo del problema y como lo podemos solucionar, seguiremos la teoría del ejemplo anterior</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> oldNinjas <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'Ninja1'</span><span class="token punctuation">,</span> <span class="token string">'Ninja2'</span><span class="token punctuation">]</span>
<span class="token keyword">const</span> newNinja <span class="token operator">=</span> <span class="token string">'Ninja3'</span>
<span class="token keyword">const</span> <span class="token function-variable function">addNinja</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">actualNinjas<span class="token punctuation">,</span> newNinja</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">const</span> ninjas <span class="token operator">=</span> actualNinjas
ninjas<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>newNinja<span class="token punctuation">)</span>
<span class="token keyword">return</span> ninjas
<span class="token punctuation">}</span>
<span class="token keyword">const</span> totalNinjas <span class="token operator">=</span> <span class="token function">addNinja</span><span class="token punctuation">(</span>oldNinjas<span class="token punctuation">,</span> newNinja<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>totalNinjas<span class="token punctuation">)</span> <span class="token comment">// result <--["Ninja1","Ninja2","Ninja3"]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>oldNinjas<span class="token punctuation">)</span> <span class="token comment">// result <--["Ninja1","Ninja2","Ninja3"]</span>
</code></pre></div>
<p>Es un ejemplo muy forzado lo sé, pero creo que se puede captar el concepto, aunque le estemos enviando por parámetro los ninjas actuales al ser realmente una referencia modificamos el valor de <em>oldNinjas</em> queramos o no, en este caso vemos como nuestra función <strong>no es pura</strong>, tiene efectos colaterales que no deseamos. En este caso una posible solución podía ser esta:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> oldNinjas <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'Ninja1'</span><span class="token punctuation">,</span> <span class="token string">'Ninja2'</span><span class="token punctuation">]</span>
<span class="token keyword">const</span> newNinja <span class="token operator">=</span> <span class="token string">'Ninja3'</span>
<span class="token keyword">const</span> <span class="token function-variable function">addNinja</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">actualNinjas<span class="token punctuation">,</span> newNinja</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> actualNinjas<span class="token punctuation">.</span><span class="token function">concat</span><span class="token punctuation">(</span>newNinja<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> totalNinjas <span class="token operator">=</span> <span class="token function">addNinja</span><span class="token punctuation">(</span>oldNinjas<span class="token punctuation">,</span> newNinja<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>totalNinjas<span class="token punctuation">)</span> <span class="token comment">// result <--["Ninja1","Ninja2","Ninja3"]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>oldNinjas<span class="token punctuation">)</span> <span class="token comment">// result <--["Ninja1","Ninja2"]</span>
</code></pre></div>
<p>Concat es un método de los arrays que realmente no modifica el objeto original, si no que devuelve uno nuevo, con esto cumpliriamos siempre con la funcionalidad en cuestión y no modificamos nada que realmente no queremos. Esta solo es una forma de cumplir con lo que estamos buscando sé que tenemos otras muchas opciones esto es solo a nivel de ejemplo.</p>
<p>Vamos a por la siguiente</p>
<h2 id="funcionesdeordensuperior">Funciones de orden superior</h2>
<p>Esto viene también de la mano de las <strong>funciones como ciudadanos de primera clase</strong>, es decir, las funciones se pueden tratar como cualquier otra variable u objeto del lenguaje y hacen uso de otras funciones.</p>
<p>Estas características estamos usandolas habitualmente en javascript aunque puede que no seamos conscientes del todo, por ejemplo cuando hacemos usos de callbacks o trabajamos con promesas ya estamos haciendo uso de estas características. Veamos un ejemplo sencillo que hace uso de las 2 características</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">calculator</span> <span class="token punctuation">(</span><span class="token parameter">number<span class="token punctuation">,</span> operation</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">operation</span> <span class="token punctuation">(</span>number<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">plus2</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> number <span class="token operator">+</span> <span class="token number">2</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">squared</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> number<span class="token operator">**</span><span class="token number">2</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> twoPlusTwo <span class="token operator">=</span> <span class="token function">calculator</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> plus2<span class="token punctuation">)</span>
<span class="token keyword">const</span> threeSquared <span class="token operator">=</span> <span class="token function">calculator</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> squared<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>twoPlusTwo<span class="token punctuation">)</span> <span class="token comment">// 4</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>threeSquared<span class="token punctuation">)</span> <span class="token comment">// 9</span>
</code></pre></div>
<p>Como vemos estamos pasando por parámetro las operaciones que queremos realizar y luego ya <em>calculator</em> hace uso de el directamente, creo que más o menos se entiende.</p>
<p>Veamos el siguiente punto.</p>
<h2 id="currificacinyaplicacinparcial">Currificación y aplicación parcial</h2>
<p>A menudo estos conceptos se separan porque puramente hablando no son lo mismo, pero hacen uso de la misma funcionalidad realmente lo que cambia es la manera de aplicarla.<br>
Para hablar de esto (y aunque no quería meterme en tecnicismos) tengo que introducir el concepto de <em>aridad</em>. La aridad de una función básicamente es la cantidad de parámetros que tiene un método:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">calculator</span> <span class="token punctuation">(</span><span class="token parameter">number<span class="token punctuation">,</span> operation</span><span class="token punctuation">)</span> <span class="token comment">// <-- aridad 2</span>
</code></pre></div>
<p>Bien viendo lo que es la aridad ahora veamos una funcionalidad muy util que tenemos con javascript, que viene de la mano de la de las funciones puras. Como hemos comentado ya, es posible que devolvamos funciones y las recibamos por parámetro ¿no?... pues en esto es en lo que se basa tanto la aplicación parcial como la currificación, veamos un ejemplo primero:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">calculator</span> <span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">operation</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">operation</span><span class="token punctuation">(</span>number<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">plus2</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> number <span class="token operator">+</span> <span class="token number">2</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> <span class="token function-variable function">squared</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">number</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> number<span class="token operator">**</span><span class="token number">2</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> baseNumber <span class="token operator">=</span> <span class="token function">calculator</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>baseNumber<span class="token punctuation">)</span> <span class="token comment">// function (operation) { return operation(number); }</span>
<span class="token keyword">const</span> twoPlusTwo <span class="token operator">=</span> <span class="token function">baseNumber</span><span class="token punctuation">(</span>plus2<span class="token punctuation">)</span>
<span class="token keyword">const</span> twoSquared <span class="token operator">=</span> <span class="token function">baseNumber</span><span class="token punctuation">(</span>squared<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>twoPlusTwo<span class="token punctuation">)</span> <span class="token comment">// 4</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>twoSquared<span class="token punctuation">)</span> <span class="token comment">// 4</span>
</code></pre></div>
<p>Lo importante ahora mismo es la función <em>calculator</em>, como vemos lo primero que hace la función es devolver otra función, si nos fijamos en el console.log de <em>baseNumber</em> vemos como realmente es una función que espera una operación y simplemente lo que tenemos es ya un número preparado para realizar la operación.</p>
<p>Visto esto veamos lo que es aplicación parcial con un ejemplo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">createPlayer</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> health</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter">weapon</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span>
name<span class="token punctuation">,</span>
health<span class="token punctuation">,</span>
weapon
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> playerBase <span class="token operator">=</span> <span class="token function">createPlayer</span><span class="token punctuation">(</span><span class="token string">'DevNinja'</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> availableWeapons <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'SuperGun'</span><span class="token punctuation">,</span> <span class="token string">'Katana'</span><span class="token punctuation">,</span> <span class="token string">'Smoke Grenade'</span><span class="token punctuation">]</span>
<span class="token keyword">const</span> playerWeapon <span class="token operator">=</span> availableWeapons<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> availableWeapons<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">const</span> player1 <span class="token operator">=</span> <span class="token function">playerBase</span><span class="token punctuation">(</span>playerWeapon<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>player1<span class="token punctuation">)</span> <span class="token comment">// { name:"DevNinja", health:1000, weapon:"Katana" }</span>
</code></pre></div>
<p>Vuelvo a comentar que esto es un poco forzado, pero nos vale para el concepto. Si nos fijamos ahora usamos arrow functions que son más comodas para hacer estas cosas.<br>
Pues bien en este caso <em>createPlayer</em> lo primero recibe el nombre y el valor de salud y se queda "a la espera" de que el sistema le aplique un arma al jugador, esto es lo que seria la aplicación parcial, podemos definirlo como una ejecución de una función por pasos, pero como vemos en este caso tenemos una aridad inicial de 2 y luego de 1, esta situación de aridad es la diferencia principal entre aplicación parcial y currificación. La currificación tendría siempre aridad 1, es decir:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">createPlayer</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter">health</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token parameter">weapon</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">{</span>
name<span class="token punctuation">,</span>
health<span class="token punctuation">,</span>
weapon
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> playerBase <span class="token operator">=</span> <span class="token function">createPlayer</span><span class="token punctuation">(</span><span class="token string">'DevNinja'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> playerHealh <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> playerWithInitialHealh <span class="token operator">=</span> <span class="token function">playerBase</span><span class="token punctuation">(</span>playerHealh<span class="token punctuation">)</span>
<span class="token keyword">const</span> availableWeapons <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'SuperGun'</span><span class="token punctuation">,</span> <span class="token string">'Katana'</span><span class="token punctuation">,</span> <span class="token string">'Smoke Grenade'</span><span class="token punctuation">]</span>
<span class="token keyword">const</span> playerWeapon <span class="token operator">=</span> availableWeapons<span class="token punctuation">[</span>Math<span class="token punctuation">.</span><span class="token function">floor</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> availableWeapons<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token keyword">const</span> player1 <span class="token operator">=</span> <span class="token function">playerWithInitialHealh</span><span class="token punctuation">(</span>playerWeapon<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>player1<span class="token punctuation">)</span> <span class="token comment">// { name:"DevNinja", health:428, weapon:"Smoke Grenade" }</span>
</code></pre></div>
<p>Ahora tenemos que siempre trabajamos con una aridad de 1, lo que modulariza bastante el uso de nuestro método <em>createPlayer</em>, haciendo posible que hagamos cualquier operación entre cada paso de la función.</p>
<p>Bueno creo que más o menos se entienden estos conceptos, voy un poco rápido con esto porque existen multitud de ejemplos y explicaciones al respecto por internet, si algo no esta claro recomiendo investigar un poco más, en esta serie nos detendremos un poco en conceptos más complejos como los <em>functores y las monadas</em> que son algo más duros para entenderlos.</p>
<p>Nos vemos en el siguiente donde hablaremos de la <strong>Composición de funciones</strong> un abrazoooooo Ninjaaas</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[JS Algoritmos y estructuras de datos III: Patrón Multiple Pointers]]></title><description><![CDATA[Continuemos con nuestra serie sobre algoritmos y estructuras de datos, en este
caso vamos a ver el patrón Multiple pointers.
Multiple pointers pattern
Este patrón, pensando en arrays, se basa en crear puntos o valores que
corresponden a una posición y moverse al principio, el medio o al final según
ciertos condiciones. Este patrón es muy eficiente para reducir al mínimo posible
la complejidad espacial.
Pensemos lo primero en un ejemplo donde poder usarlo, vamos a crear un método
que dentro de ]]></description><link>https://jlgarcia.fulldev.ninja/js-algoritmos-y-estructurdas/</link><guid isPermaLink="false">Ghost__Post__5c3e0fda2dd6610fd828cb5b</guid><category><![CDATA[algoritmos]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 09 Nov 2020 09:06:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640.png" alt="JS Algoritmos y estructuras de datos III: Patrón Multiple Pointers"/><p>Continuemos con nuestra serie sobre algoritmos y estructuras de datos, en este caso vamos a ver el patrón <strong>Multiple pointers</strong>.</p>
<h3 id="multiplepointerspattern">Multiple pointers pattern</h3>
<p>Este patrón, pensando en arrays, se basa en crear puntos o valores que corresponden a una posición y moverse al principio, el medio o al final según ciertos condiciones. Este patrón es muy eficiente para reducir al mínimo posible la complejidad espacial.</p>
<p>Pensemos lo primero en un ejemplo donde poder usarlo, vamos a crear un método que dentro de un array ordenado nos devuelva la primera pareja que sume 0.</p>
<p>En un primer momento lo que nos vendría a la cabeza sería hacer 2 loops recorriendo dos veces todo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">sumZero</span> <span class="token punctuation">(</span><span class="token parameter">arr</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator"><</span> arr<span class="token punctuation">.</span>length<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">+</span> arr<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">[</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> arr<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">sumZero</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// [-2, 2]</span>
</code></pre></div>
<p>Este algoritmo tiene una complejidad:</p>
<ul>
<li>Temporal <strong>O(n^2)</strong></li>
<li>Espacial <strong>O(1)</strong></li>
</ul>
<p>Que aunque en complejidad espacial no esta mal en temporal se nos puede ir de las manos.</p>
<p>Veamos una solución algo mejor usando este patrón, pero antes de continuar quiero recalcar que esto es posible porque <strong>el array esta ordenado</strong>, en general muchos de los algoritmos cuentan con esto para poder resolverse (más adelante veremos varios de los mejores patrones de ordenación). Vamos con la solución:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">sumZero</span> <span class="token punctuation">(</span><span class="token parameter">arr</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Establecemos los puntos de inicio (multiple pointers u know)</span>
<span class="token keyword">let</span> left <span class="token operator">=</span> <span class="token number">0</span>
<span class="token keyword">let</span> right <span class="token operator">=</span> arr<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>left <span class="token operator"><</span> right<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// para no pasarnos</span>
<span class="token keyword">let</span> sum <span class="token operator">=</span> arr<span class="token punctuation">[</span>left<span class="token punctuation">]</span> <span class="token operator">+</span> arr<span class="token punctuation">[</span>right<span class="token punctuation">]</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>sum <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">[</span>arr<span class="token punctuation">[</span>left<span class="token punctuation">]</span><span class="token punctuation">,</span> arr<span class="token punctuation">[</span>right<span class="token punctuation">]</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>sum <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
right<span class="token operator">--</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
left<span class="token operator">++</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">sumZero</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// [-2, 2]</span>
</code></pre></div>
<p>En esta solución lo que hacemos es ir moviendo nuestros puntos y comprobando si cumple la condición de ser igual a 0. Como es un array ordenado si la suma es mayor de 0 quiere decir que el valor es superior por la derecha del 0 (nuestra variable right) y si el valor es negativo quiere decir que el valor es superior por la izquierda (varible left). Según cual sea de los dos lo que hacemos es ir moviendo nuestros puntos hasta que en algun momento de 0 o hayamos recorrido todos los valores por entre ambos puntos.</p>
<p>Esta solución tiene una complejidad de:</p>
<ul>
<li>Temporal <strong>O(n)</strong>, solo recorremos una vez los valores.</li>
<li>Espacial <strong>O(1)</strong></li>
</ul>
<p>Veamos un ejemplo algo más dificil, en este caso queremos comprobar si un string es una subsecuencia de otro, o más bien si aparece como una secuencia de los carácteres de otro pero de manera ordenada, es decir, si <em>word</em> estaría dentro de <em>hello world</em> en orden (no es word pero el orden es primero w y ultimo d)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">isInString</span> <span class="token punctuation">(</span><span class="token parameter">string1<span class="token punctuation">,</span> string2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Establecemos los puntos de inicio (multiple pointers u know)</span>
<span class="token keyword">let</span> s1 <span class="token operator">=</span> <span class="token number">0</span>
<span class="token keyword">let</span> s2 <span class="token operator">=</span> <span class="token number">0</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>s2 <span class="token operator"><</span> string2<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// para no pasarnos</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>string1<span class="token punctuation">[</span>s1<span class="token punctuation">]</span> <span class="token operator">===</span> string2<span class="token punctuation">[</span>s2<span class="token punctuation">]</span><span class="token punctuation">)</span> s1<span class="token operator">++</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>s1 <span class="token operator">===</span> string1<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">true</span>
s2<span class="token operator">++</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token boolean">false</span>
<span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">isInString</span><span class="token punctuation">(</span><span class="token string">'ninja'</span><span class="token punctuation">,</span> <span class="token string">'new in jail'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true si quitamos lo que sobra n__ in ja__</span>
</code></pre></div>
<p>En este caso tenemos dos strings que debemos recorrer y queremos comprobar si el primero <em>string1</em> es una subsecuencia del segundo <em>string2</em>. En este caso nuestros puntos los situamos al inicio de cada string y vamos recorriendo, si encontramos una coincidencia de la primera posición del string1 en la primera posición del string2, movemos la posición del string1 si no, movemos la posición del string2 y así sucesivamente una vez que hayamos recorrido todo el string1 quiere decir que ya tenemos coincidencia y devolvemos <em>true</em>, en el caso de que la posición de string2 sea mayor que el tamaño del string2 quiere decir que no tenemos coincidencias por lo que devolvemos <em>false</em>.</p>
<p>Este patrón como vemos es muy util para comparar de alguna forma ya sea un elemento o varios y no tener que recorrerlos todos <strong>n</strong> veces convirtiendo la complejidad temporal en <strong>O(n^x)</strong> siendo x la cantidad de veces (o la cantidad de elementos) que tenemos que recorrer un elemento (o varios) al completo. En este caso por ejemplo tenemos una complejidad de:</p>
<ul>
<li>Temporal <strong>O(n + m)</strong>. Dos strings que en el peor de los casos recorreremos enteros pero solo una vez cada uno.</li>
<li>Espacial <strong>O(1)</strong></li>
</ul>
<p>Hasta aquí lo referente a este patrón de resolución de problemas, nos vemos en el siguienteeee un abraazoooo</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Javascript Funcional I: Intro e Inmutabilidad]]></title><description><![CDATA[Empezamos nueva serie donde explicaremos los conceptos básicos de la
programación funcional orientados al mundo JavaScript.
Empecemos por lo básico, ¿qué es la programación funcional? Citando directamente
a la wikipedia
> En informática, la programación funcional es un paradigma de programación
declarativa basado en el uso de verdaderas funciones matemáticas. En este estilo
de programación las funciones son ciudadanas de primera clase, porque sus
expresiones pueden ser asignadas a variables com]]></description><link>https://jlgarcia.fulldev.ninja/javascript-funcional-intro/</link><guid isPermaLink="false">Ghost__Post__5fa68e1fa6c0f5058bff43ac</guid><category><![CDATA[funcional]]></category><category><![CDATA[ramda]]></category><category><![CDATA[javascript]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Sat, 07 Nov 2020 13:57:05 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/28e76839a7fb382fbbe244b857f2980c/Capture-5.jpeg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/28e76839a7fb382fbbe244b857f2980c/Capture-5.jpeg" alt="Javascript Funcional I: Intro e Inmutabilidad"/><p>Empezamos nueva serie donde explicaremos los conceptos básicos de la programación funcional orientados al mundo JavaScript.<br>
Empecemos por lo básico, ¿qué es la programación funcional? Citando directamente a la wikipedia</br></p>
<blockquote>
<p>En informática, la programación funcional es un paradigma de programación declarativa basado en el uso de verdaderas funciones matemáticas. En este estilo de programación las funciones son ciudadanas de primera clase, porque sus expresiones pueden ser asignadas a variables como se haría con cualquier otro valor; además de que pueden crearse funciones de orden superior.</p>
</blockquote>
<p>Digamos que es un parádigma donde todo esta basado en algún tipo de función o teoría matemática (su centro fué el cálculo lambda) y nos obliga a realizar abstracciones que no son habituales en paradigmas más habituales como la programación orientada a objetos, pero esto no implica que tengamos que ser licenciados en matemáticas para porder usarlo y beneficiarnos de sus ventajas.</p>
<p>Las carácteristicas y ventajas que se suelen comentar sobre este paradigma:</p>
<ul>
<li>En lugar de centrarse en el <strong>¿cómo?</strong> se centra en el <strong>¿qué?</strong> queremos hacer, lo que hace que nos abstraigamos un poco más del problema que queremos resolver.</li>
<li>Como su nombre indica está básado en el trabajo con funciones, practicamente todo es una función, y se tiende a la realización de funciones con un trabajo mínimo y específico, por lo que tendremos funciones pequeñas donde por ejemplo si estamos trabajando en un carrito de la compra existirian métodos como <strong>sumar precio o añadir descuento</strong>, y estos métodos devolverían siempre lo mismo siempre y cuando sus valores de entrada fueran los mismos. Muchos se preguntaran pero con esto ¿cómo contruimos toda la lógica de un carrito de la compra?... esto se basaría en la <strong>composición de funciones</strong>, es decir, cogemos esas funciones pequeñas que hemos creado y <em>componemos</em> una lógica que cumpla con nuestras necesidades. Siguiendo con el ejemplo del carrito si se añade algo al carrito de la compra tendriamos un método <strong>añadir producto</strong> que lo que podría hacer sería <strong>incluir producto al listado, sumar precio y aplicar descuento</strong>. Esto ya lo veremos más adelante.</li>
<li>Usa lo que se conoce como <strong>funciones puras</strong>, estás funciones se llaman así porque no tienen efectos colaterales, es decir, no cambián ni hacen nada fuera del propio método (incluso un console.log es considerado un efecto colateral), por eso siempre obtenemos el mismo resultado pasandole los mismos parámetros.</li>
<li>Al basarse en las funciones puras es un lenguaje muy apto para el paralelismo, ya que no modifica no accede a valores externos no tendremos problemas de <em>race condition</em> o casi cualquier otro que pudiera venir surgido de la concurrencia.</li>
<li>Las funciones son <strong>ciudadanos de primera clase</strong>, son <strong>funciones de orden superior</strong>. Ambos casos están relacionados, las funciones de orden superior se las llama asi cuando son funciones que actuan directamente sobre otras funciones y entedemos funciones como ciudadanos de primera clase cuando las funciones pueden ser tratadas como cualquier otro elemento del lenguaje, es decir se pueden pasar como parámetros o se pueden devolver funciones directamente como resultado.</li>
<li>Hace uso de lo que se conoce como <strong>recursividad</strong>, es decir, una función se puede llamar a si misma, por ejemplo para recorrer un árbol de directorios, podemos tener un método que sea <strong>abrir carpeta</strong> y según vaya recorriendo si el fichero en cuestión no es una carpeta lo devuelve y si es una carpeta se llama de nuevo a <strong>abrir carpeta</strong> y así hasta que se termina el arbol.</li>
<li>Todo es inmutable, es decir, no se modifica nada existente se crean elementos nuevos dentro de las propias funciones con los cambios necesarios.</li>
<li>Suele ser un código más expresivo</li>
<li>Es un código más facilmente testeable</li>
<li>Se tiende menos a la repetición de código, ya que todo está planteado como mini funciones con un trabajo en concreto, solo tenemos que reutilizarlas cuando toque o componer funciones que las usen.</li>
</ul>
<p>Si me pongo podría seguir escribiendo características pero bueno en general creo que nos hacemos una idea de lo que os estoy vendiendo aquí y por mucho que siga hasta que no se vean ejemplos concretos no entenderemos lo que es esto realmente por lo que vamos a empezar hablando de <strong>Javascript e Inmutabilidad</strong></p>
<h2 id="javascriptfuncional">Javascript funcional</h2>
<p>Primero hablemos un poco del caso concreto de Javascript como lenguaje funcional. Para mi Javascript es de los mejores lenguajes que existen por su versatilidad y sus minimas obligaciones, es decir, <strong>podemos hacer lo que nos de la gana</strong>. Esto en general suele crear incovenientes porque no tenemos normas que seguir como puede ser establecer un tipo a las variables, como ya sabemos una variable ahora puede ser un número y más tarde convertirse en un string sin ni siquiera hacer un casting de tipos. Esta libertad viene de la mano de multitud de posibles errores si nos descuidamos con estas cosas (que no suelen pasar en otros lenguajes).<br>
Pero gracias a esto podemos programar como más nos convenga o nos guste y combinar soluciones de distintos tipos para nuestro beneficio.<br>
Como sabemos en Javascript practicamente todo es un tipo Object o parte de un tipo Object, incluso las funciones, esto nos permite usar las funciones como cualquier otro objeto: asignarlo a variables, pasarlas por parámetro, devolver funciones como resultado.... como hemos dicho al principio esto es lo básico para que un lenguaje sea funcional por lo que ya tenemos esta posibilidad, veamos como podemos cumplir con las carácteristicas básicas de un lenguaje funcional: <strong>Inmutabilidad</strong>, <strong>Funciones puras</strong>, <strong>Funciones de orden superior</strong>, <strong>Uso de currificación</strong> y <strong>composición de funciones</strong></br></br></p>
<h3 id="inmutabilidad">Inmutabilidad</h3>
<p>Veamos lo primero el problema en cuestión</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> oldNinjas <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'Ninja1'</span><span class="token punctuation">,</span> <span class="token string">'Ninja2'</span><span class="token punctuation">]</span>
<span class="token keyword">const</span> newNinja <span class="token operator">=</span> <span class="token string">'Ninja3'</span>
<span class="token keyword">const</span> totalNinjas <span class="token operator">=</span> oldNinjas
totalNinjas<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>newNinja<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>oldNinjas<span class="token punctuation">)</span> <span class="token operator"><</span><span class="token operator">--</span> Result<span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"Ninja1"</span><span class="token punctuation">,</span> <span class="token string">"Ninja2"</span><span class="token punctuation">,</span> <span class="token string">"Ninja3"</span> <span class="token punctuation">]</span>
</code></pre></div>
<p>Como vemos se ha modificado <em>oldNinjas</em> también, esto es funcionamiento interno de Javascript, digamos que lo que tenemos dentro de <em>totalNinjas</em> es una referencia en memoria a <em>oldNinjas</em> por eso hagamos lo que hagamos con totalNinjas se verá reproducido en oldNinjas, ojo que es un ejemplo un poco forzado para ver el caso concreto, con un <strong>oldNinjas.concat</strong> no tendriamos este problema.</p>
<p>Suponiendo que tenemos este problema tenemos varias opciones para resolverlo, la primera hacemos un <strong>freeze</strong> sobre oldNinjas para que no se pueda modificar hagamos lo que hagamos (nos daria error) y a continuación realizamos una copia del array:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> oldNinjas <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">freeze</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'Ninja1'</span><span class="token punctuation">,</span> <span class="token string">'Ninja2'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> newNinja <span class="token operator">=</span> <span class="token string">'Ninja3'</span>
<span class="token keyword">const</span> totalNinjas <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token operator">...</span>oldNinjas<span class="token punctuation">]</span> <span class="token comment">// Copiamos</span>
totalNinjas<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>newNinja<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>totalNinjas<span class="token punctuation">)</span> <span class="token comment">// result --> [ "Ninja1", "Ninja2", "Ninja3"]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>oldNinjas<span class="token punctuation">)</span> <span class="token comment">// result --> [ "Ninja1", "Ninja2"]</span>
</code></pre></div>
<p>Esta sería una opción para cumplir con este principio, otra es usar alguna librería funcional que haga esto por nosotros, a mí la que más me gusta es <a href="https://ramdajs.com/">Ramda</a>, es muy eficiente y cumple más o menos bien con los requerimientos funcionales</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token constant">R</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'ramda'</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> oldNinjas <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">freeze</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'Ninja1'</span><span class="token punctuation">,</span> <span class="token string">'Ninja2'</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token keyword">const</span> newNinja <span class="token operator">=</span> <span class="token string">'Ninja3'</span>
<span class="token keyword">const</span> totalNinjas <span class="token operator">=</span> <span class="token constant">R</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>newNinja<span class="token punctuation">,</span> oldNinjas<span class="token punctuation">)</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>totalNinjas<span class="token punctuation">)</span> <span class="token comment">// result --> [ "Ninja1", "Ninja2", "Ninja3"]</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>oldNinjas<span class="token punctuation">)</span> <span class="token comment">// result --> [ "Ninja1", "Ninja2"]</span>
</code></pre></div>
<p>Esto es un ejemplo de como podemos cumplir con el principio de inmutabalidad necesario en la programación funcional.</p>
<p>Creo que por el momento es suficiente para un único post, continuaremos con los siguientes conceptos en proximos capítulos, cuadaaaos y un abrazooooooo</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[MongoDB Index Ninja 2.0]]></title><description><![CDATA[Antes de nada tenemos un repo con un script para insertar los documentos que
usamos de ejemplo:
Mongo_index_explain [https://github.com/jlgarciaap/mongo_index_explain]
En general sabemos que es un índice de mongo pero hablemos un poco más en
profundidad. Si no índicamos un índice cuando creamos una colección mongo, por
defecto, nos creará un índice con el campo _id de tipo único (no se puede
repetir el campo).
Cuando creamos un índice mongo crea otra especie de mini colección solo con los
dat]]></description><link>https://jlgarcia.fulldev.ninja/mongodb-ninja-iv-index-ninja-2-0/</link><guid isPermaLink="false">Ghost__Post__5e19a48ee3717304bd77a170</guid><category><![CDATA[mongodb]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Sun, 12 Jan 2020 18:27:09 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner.png" alt="MongoDB Index Ninja 2.0"/><p>Antes de nada tenemos un repo con un script para insertar los documentos que usamos de ejemplo:</p>
<p><a href="https://github.com/jlgarciaap/mongo_index_explain">Mongo_index_explain</a></p>
<p>En general sabemos que es un índice de mongo pero hablemos un poco más en profundidad. Si no índicamos un índice cuando creamos una colección mongo, por defecto, nos creará un índice con el campo <strong>_id</strong> de tipo <strong>único</strong> (no se puede repetir el campo).</p>
<p>Cuando creamos un índice mongo crea otra especie de mini colección solo con los datos que le indicamos en el índice, ordenados de la manera que le indiquemos y apuntando al documento al que hacen referencia. Cada índice tiene una especie de firma, es decir, se le asigna un nombre para identificarlo usando los campos del índice y mongo recorre su lista de indices hasta que encuentra una coincidencia, es decir, si buscamos por dos campos intentará encontrar uno donde coincida la firma de esos campos y si no busca separando los campos hasta que encuentra una coincidencia, si no la encuentra continuará con una búsqueda sin índice.<br>
Pero antes de ver esto vayamos paso a paso.<br>
Mongo sigue la misma teoría que el resto de bases de datos con sus índices, usa lo que se conoce como <strong>Binary Tree Sort</strong>, es un tipo de algoritmo de búsqueda bastante eficiente para estas cosas <a href="/mongodb-ninja-iv-index-ninja/">Más info</a></br></br></p>
<h3 id="sintaxisbsicadecreacindendices">Sintaxis básica de creación de índices</h3>
<p>Antes de ver los tipos de índices la sintaxis básica de creación de índices es la siguiente</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token property">lastName</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Siendo <strong>lastName</strong> el campo del que queremos el índice y <strong>-1</strong> es la ordenación si lo queremos ascendente pondremos un <strong>1</strong>, si lo queremos descendente <strong>-1</strong></p>
<p>Más adelante veremos las opciones de creación de los índices.</p>
<h3 id="tiposdendices">Tipos de índices</h3>
<h4 id="singlefieldunsolocampo">Single field (un solo campo)</h4>
<p>Como dice el nombre tenemos un tipo de índice donde lo creamos solo con un campo, es decir:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token property">lastName</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Veamos un ejemplo con la diferencia de tener un índice a no tenerlo. En la colección de prueba que tenemos vamos a realizar un búsqueda por lastName y veamos lo que tarda. Busquemos con el siguiente comando primero en la colección sin índice:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'noindex'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">lastName</span><span class="token operator">:</span> <span class="token string">'Master'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Esto nos da que nos ha traido 10 elemento en un tiempo de <strong>4190 ms</strong></p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-11-a-las-18.50.57.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Ahora vamos a crear un índice en la colección para ello con este comando:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">lastName</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>(más adelante veremos como ver los índices que tenemos y cosas así)</p>
<p>Ahora ejecutemos la misma búsqueda pero dentro de la colección con índice que acabamos de crear:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">lastName</span><span class="token operator">:</span> <span class="token string">'Master'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Esto nos da que nos ha traido 10 elementos en un brutal tiempo de <strong>10ms</strong> la primera vez y las siguientes a <strong>0ms</strong></p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-11-a-las-18.58.16.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Ahora se puede ver un poco la potencia que nos proveen los índices.</p>
<p>Veamos otro ejemplo que no va también, vamos a crear primero un índice de un campo con esto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Tenemos una colección donde la gran mayoría de los 2000000 de elementos tienen la misma ciudad, por lo que ahora pasa una cosa curiosa, veamos la búsqueda con indice</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Tarda unos <strong>8873ms</strong>, ahora veamos la búsqueda normal</p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-11-a-las-19.31.58.png" alt="MongoDB Index Ninja 2.0"/></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'noindex'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Sorprendentemente tarda <strong>3963ms</strong> mucho menos</p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-11-a-las-19.33.46.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Pero porqué?? Bueno el algoritmo de búsqueda binaria que tienen los índices no es eficiente para este tipo de colecciones donde la mayoria de elementos son iguales, para que este algoritmo haga su magia necesitamos que los elementos a buscar sean la mayoría diferentes, por eso en este caso es más eficiente la búsqueda habitual donde recorre todos y descarta los que no necesita.</p>
<p>Si tenemos esta casuística donde un montón de campos son iguales lo más probable es que filtremos por algún campo más, es decir que creemos un índice de tipo <strong>compound</strong> (los veremos a continuación), pero si quisieramos realizar una busqueda sin índice, en mongo se conoce como búsqueda <strong>natural</strong> y aunque no se suele comentar esto mucho por los mares digitales, tenemos la posibilidad de forzarlo, solo tenemos que sugerirlo de esta manera:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">hint</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property"><span class="token keyword">$natural</span></span> <span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p><strong>hint</strong> es uno de los extras que podemos indicar en las busquedas para sugerir un índice u otro según el nombre, podemos ponerlo de la misma manera que pusimos al crear el índice:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">hint</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>O con el nombre de índice que se crea:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">hint</span><span class="token punctuation">(</span><span class="token string">"city_-1"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Los podemos ver por ejemplo desde robo3t</p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-11-a-las-19.49.54.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Visto este caso especial pasemos a los índices compuestos donde podemos ver búsquedas eficientes por varios campos</p>
<h4 id="compoundfieldscompuestoobsicamentevarioscampos">Compound fields (compuesto....o básicamente varios campos)</h4>
<p>Los siguientes índices son los que involucran a varios campos dentro de nuestras colecciones, estos siguen un orden según como los escribamos, la sintaxis básica sería:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">field1</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">,</span> <span class="token property">field2</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Lo que hace este índice es crear un índice partiendo principalmente del <code class="language-text">field1</code> con un orden ascendente y dentro de los field1 que coincidan los ordena según el <code class="language-text">field2</code> de manera descendente.</p>
<p>En nuestro caso crearemos un índice por ciudad e email, recordemos que en ciudad tenemos 1999000 veces la misma ciudad y antes ha tardado mogollón</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Ahora veamos la búsqueda sín indice:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'noindex'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span> <span class="token string">'NinjaMaster@email.com'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Ha tardado <strong>5112ms</strong> que no está nada mal pensando en la búsqueda anterior, pero ahora veamos la búsqueda con el índice</p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-11-a-las-19.58.25.png" alt="MongoDB Index Ninja 2.0"/></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span> <span class="token string">'NinjaMaster@email.com'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Sorprendetemente ha tardado solo <strong>12ms</strong></p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-11-a-las-19.54.52.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Cosas que tenemos que tener en cuenta de los índices compuestos:</p>
<ul>
<li>Tienen un límite de 32 campos</li>
<li>En un principio el orden en que definamos el índice no influye demasiado (menos en los $fullText que usaría como filtro inicial para hacer el de texto) a la hora de buscar pero si a la hora de ordenar nosotros añadiendo un sort a continuación del find. Partiendo del índice que hemos definido anteriormente no seria lo mismo hacer esto:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">,</span> <span class="token property">lastName</span><span class="token operator">:</span> <span class="token string">'Master'</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span> <span class="token string">'NinjaMaster@email.com'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">'executionStats'</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Que hacer esto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">,</span> <span class="token property">lastName</span><span class="token operator">:</span> <span class="token string">'Master'</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span> <span class="token string">'NinjaMaster@email.com'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">email</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">'executionStats'</span><span class="token punctuation">)</span>
</code></pre></div>
<p>O esto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">,</span> <span class="token property">lastName</span><span class="token operator">:</span> <span class="token string">'Master'</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span> <span class="token string">'NinjaMaster@email.com'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">'executionStats'</span><span class="token punctuation">)</span>
</code></pre></div>
<p>La primera usa el índice directamente y no tiene que hacer nada más:</p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-13-a-las-20.16.08.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Las otras dos pasan del índice para hacer la ordenación, la segunda porque directamente ordenamo primero por email y la segunda porque no es ninguna de las opciones factibles en cuanto a dirección <strong>un índice usa solo dos tipos de ordenaciones: la misma con la que se ha definido y la que es directamente opuesta, es decir, si definimos un índice con <code class="language-text">1,-1,1</code>, usaría el índice para ordenar bajo esa definición o con <code class="language-text">-1,1-1</code></strong></p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-13-a-las-20.17.13.png" alt="MongoDB Index Ninja 2.0"/></p>
<h3 id="multikeyindexindiceconarraysenresumen">Multikey Index (Indice con arrays en resumen)</h3>
<p>Este tipo de índice lo crea automáticamente mongo al detectar un campo de tipo array, en un principio podemos pensar que no tiene mucho de especial, pero realmente tenemos que tener en cuenta que el índice creará una entrada por cada elemento del array. Supongamos que además de ciudades tenemos un array de poblaciones donde por ejemplo puede trabajar ese usuario, si alguien de Madrid tiene de poblaciones disponibles Coslada, Vicalvaro, Mordor.... nos creara:</p>
<p>Madrid + Coslada<br>
Madrid + Vicalcaro<br>
Madrid + Mordor<br>
...</br></br></br></p>
<p><strong>Esto es importante a la hora de controlar el tamaño del índice, los índices ocupan espacio.....por si no lo habías pensado y también consumen al rehacerse, cada vez que se escribe se vuelve a indexar</strong></p>
<p>A tener en cuenta:</p>
<ul>
<li>Solo podemos tener índices con uno de los valores de tipo array, si intentamos tener dos nos dirá que nos dediquemos a la pintura</li>
<li>Si tenemos un índice con array e intentamos insertar en otro de los campos del índice un array nos dirá otra vez que lo nuestro es el arte</li>
<li>Podemos crear índices con campos con arrays de documentos, que funcionarían igual que los arrays normales si le indicamos uno de los campos del documento</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">'tags.front'</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">'tags.front'</span><span class="token operator">:</span> <span class="token string">'Vuejs'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">'executionStats'</span><span class="token punctuation">)</span>
</code></pre></div>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-13-a-las-20.29.08.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Si no le indicamos un campo en concreto nos creará un índice pero solo funcionara con documentos completos, no con campos específicos. Borramos el índice anterior y creamos este:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">'tags'</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Ahora realizamos la misma búsqueda anterior:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">'tags.front'</span><span class="token operator">:</span> <span class="token string">'Vuejs'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">'executionStats'</span><span class="token punctuation">)</span>
</code></pre></div>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-13-a-las-20.36.34.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Lo notamos con el tiempo que tarda pero podemos vemos como hace la búsqueda básica con <strong>COLLSCAN</strong>.<br>
Sin embargo si búscamos un documento al completo:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">'tags'</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">front</span><span class="token operator">:</span> <span class="token string">'Vuejs'</span><span class="token punctuation">,</span>
<span class="token property">back</span><span class="token operator">:</span> <span class="token string">'Node'</span>
<span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">'executionStats'</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Vemos como tarda bastante menos y además nos indica que ha usado un índice</p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-13-a-las-20.38.52.png" alt="MongoDB Index Ninja 2.0"/></p>
<h3 id="indicefulltextocamposconunmontndetexto">Indice Full text(o campos con un montón de texto)</h3>
<p>El índice de texto es un tipo de indice especial que nos mejora la búsqueda con un conjunto de palabras sobre un número <strong>n</strong> de campos, es decir, nos busca en todos los campos que tenga el índice. Este índice se puede aplicar en cualquier campo de tipo string o de array con valores de tipo string, donde podemos indicarlo el idioma en cuestión para que ignore palabras comunes como 'y, o, de' en español.<br>
Por defecto se crea con idioma inglés por lo que en nuestro caso lo añadiremos a la hora de la creación del índice.</br></p>
<p>Para hacernos una idea de que tiene de especial, los índices habituales lo que hacen es crearlo basandose en <code class="language-text">esto que buscas está en estos documentos</code>, sin embargo este tipo de índice lo que hace es darle la vuelta <code class="language-text">este documento tiene estas palabras</code></p>
<p>En este caso los ejemplos son un poco más complicados, las búsquedas especiales por un texto solo funcionan si tenemos un índice, por lo que , por ejemplo, en la colección <code class="language-text">noindex</code> no podremos hacer esta búsqueda, lo más parecido sería una expresión regular con un find sobre los campos que quisieramos realizar la búsqueda y evidentemente tardará un poco más, veamos un ejemplo. Para la pruebas tener en cuenta que no seria lo mismo que un entorno de producción esto es solo para entender los conceptos, en un entorno real puede tardar más o menos la búsqueda sin índice:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'noindex'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">firstName</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">Juanchu</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span>
<span class="token property">alias</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">Juanchu</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span>
<span class="token property">bio</span><span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">Juanchu</span><span class="token regex-delimiter">/</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Esto nos da un tiempo de <strong>4429ms</strong> que no está nada mal.<br>
Creemos ahora un índice con los campos en formato texto:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">bio</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> <span class="token property">firstName</span><span class="token operator">:</span> <span class="token string">'text'</span><span class="token punctuation">,</span> <span class="token property">alias</span><span class="token operator">:</span> <span class="token string">'text'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">default_language</span><span class="token operator">:</span> <span class="token string">"spanish"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Esto tardará un montón, es un índice que tiene que comprobar todas las palabras que tienen nuestros campos de texto, y si no le ponemos el idioma bien....pues más todavía porque almacenará palabras innecesarias.</p>
<p>Ahora que ya tenemos el índice busquemos el mismo concepto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property"><span class="token keyword">$text</span></span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">$search</span><span class="token operator">:</span> <span class="token string">"Juanchu"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Ahora vuelve a tardar <strong>1ms</strong>, bastante mejor ¿no?. En un entorno con más campos se notaría más la diferencia</p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-12-a-las-11.46.42.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Para que veamos lo que nos ha encontrado</p>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-12-a-las-11.48.47.png" alt="MongoDB Index Ninja 2.0"/></p>
<p>Con esto tenemos un ejemplo, veamos ahora que epecialidades tenemos con este tipo de índice:</p>
<ul>
<li><strong>SOLO ES POSIBLE TENER UN ÍNDICE DE TIPO TEXT</strong>, es decir, si queremos añadir campos de texto, tenemos que eliminar el que tuvieramos y hacerlo de nuevo.</li>
<li>Es CASE-INSENSITIVE</li>
<li>Se le pueden indicar pesos de importancia a cada campo, esto sumará las veces que aparece la palabra que buscamos en cada campo y documento y nos los devolverá según ese orden si se lo indicamos en la busqueda.<br>
Creación:</br></li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span>
<span class="token punctuation">{</span>
<span class="token property">alias</span><span class="token operator">:</span> <span class="token string">"text"</span><span class="token punctuation">,</span>
<span class="token property">bio</span><span class="token operator">:</span> <span class="token string">"text"</span><span class="token punctuation">,</span>
<span class="token property">firstName</span><span class="token operator">:</span> <span class="token string">"text"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token property">weights</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">firstName</span><span class="token operator">:</span> <span class="token number">10</span><span class="token punctuation">,</span>
<span class="token property">alias</span><span class="token operator">:</span> <span class="token number">5</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token property">default_language</span><span class="token operator">:</span> <span class="token string">"spanish"</span> <span class="token punctuation">}</span>
<span class="token punctuation">)</span>
</code></pre></div>
<p>Esto crearía un índice con los pesos:<br>
* firstName 10<br>
* alias 5<br>
* bio 1 (by default)</br></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span>
<span class="token punctuation">{</span> <span class="token property"><span class="token keyword">$text</span></span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">$search</span><span class="token operator">:</span> <span class="token string">"Juanchu"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token property">score</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property"><span class="token keyword">$meta</span></span><span class="token operator">:</span> <span class="token string">"textScore"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">score</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property"><span class="token keyword">$meta</span></span><span class="token operator">:</span> <span class="token string">"textScore"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p><img srcset="/assets/images/2020/01/Captura-de-pantalla-2020-01-12-a-las-18.45.46.png" alt="MongoDB Index Ninja 2.0"/></p>
<ul>
<li>Los <strong>Wildcard indices</strong> o índices creados según un patrón de posibles campos, aquí solo podemos ponerlo una vez y lo que haría sería un índice con todos los campos de tipo string (más adelante veremos esto de los wildcard)</li>
<li>Sí no queremos hacer que ignore las palabras tipo <code class="language-text">y, o, de</code> que las usa como delimitadores para conjuntos, podemos índicarle <code class="language-text">language: "none"</code></li>
<li>No se puede indicar <code class="language-text">hint</code> para sugerir un índice a la hora de realizar búsquedas tipo text</li>
<li>En los índices compuestos podemos tener varios campos de tipo text pero solo podemos tener el resto de campos tipo single, es decir, no podemos tener <code class="language-text">multikeys o geospatial</code></li>
<li>Crear este tipo de índice es muy costoso a nivel de recursos, tanto en ram como en espacio y puede hacer más lenta la inserción de nuevos campos que esten bajo ese índice.</li>
</ul>
<h4 id="ndicedetextomultiidioma">Índice de texto multiidioma</h4>
<p>Esta parte require su propio título ya que tiene un poco de miga. Podemos tener colecciones en multiples idiomas y para mejorar la búsqueda bajo estos campos podemos modificar un poco los campos del documento para que mongo haga su magia con las búsquedas, añadiendo solo la traducción pertinente según el idioma que le indiquemos en el índice.<br>
Para esto tenemos que tener un campo <code class="language-text">language</code> donde indiquemos el lenguaje en cuestión del documento o campo, así a la hora de hacer el índice mongo sabra mejor que tiene que hacer con ese campo. Un ejemplo de documento podría ser este:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb"><span class="token punctuation">{</span>
<span class="token property">_id</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token property">language</span><span class="token operator">:</span> <span class="token string">"portuguese"</span><span class="token punctuation">,</span>
<span class="token property">original</span><span class="token operator">:</span> <span class="token string">"A sorte protege os audazes."</span><span class="token punctuation">,</span>
<span class="token property">translation</span><span class="token operator">:</span>
<span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token property">language</span><span class="token operator">:</span> <span class="token string">"english"</span><span class="token punctuation">,</span>
<span class="token property">quote</span><span class="token operator">:</span> <span class="token string">"Fortune favors the bold."</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token property">language</span><span class="token operator">:</span> <span class="token string">"spanish"</span><span class="token punctuation">,</span>
<span class="token property">quote</span><span class="token operator">:</span> <span class="token string">"La suerte protege a los audaces."</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Si quisieramos tener otro campo como indicador de lenguaje lo podemos indicar a la hora de crear el indice:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>quotes<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">quote</span> <span class="token operator">:</span> <span class="token string">"text"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token property">language_override</span><span class="token operator">:</span> <span class="token string">"idioma"</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<h4 id="wildcardindexindicessinsaberloscampos">Wildcard Index (indices sin saber los campos...)</h4>
<p>Esto no es muy dificil de entender, queremos crear índices donde el nombre de los campos puede ser dinámico, es decir, puede ir cambiando como puede ser un campo con metadatos que pueden ir variando, en este caso por ejemplo creariamos un índice así:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">"user_metadata.$**"</span> <span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p>Esto nos crearía un indice teniendo en cuenta que dentro de <code class="language-text">user_metadata</code> podemos tener de todo tipo de campos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb"><span class="token punctuation">{</span>
<span class="token property">user_metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"clicks"</span><span class="token operator">:</span> <span class="token number">200</span><span class="token punctuation">,</span>
<span class="token property">"views"</span><span class="token operator">:</span> <span class="token number">1000</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token property">user_metadata</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"images"</span><span class="token operator">:</span> <span class="token number">500</span><span class="token punctuation">,</span>
<span class="token property">"favorite_tags"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"games"</span><span class="token punctuation">,</span> <span class="token string">"dogs"</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Si queremos crear un índice por todos los posibles campos, simplemente</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">"$**"</span> <span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p><strong>Un índice de tipo wildcard recorrera todos los nested documents que se encuentre</strong></p>
<p>También es posible indicar este tipo de índice en campos específicos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>collection<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span>
<span class="token punctuation">{</span> <span class="token property">"$**"</span> <span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token property">"wildcardProjection"</span> <span class="token operator">:</span>
<span class="token punctuation">{</span> <span class="token property">"user_metadata"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">"games.rewards_info"</span> <span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span>
</code></pre></div>
<p>Para hacerlo usamos <code class="language-text">wildcardProjection</code> como indicador de lo que queremos hacer. Esto por ejemplo nos haría un índice con todo lo que estuviera dentro de esos dos campos.</p>
<p>También podemos excluir campos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>collection<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span>
<span class="token punctuation">{</span> <span class="token property">"$**"</span> <span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token property">"wildcardProjection"</span> <span class="token operator">:</span>
<span class="token punctuation">{</span> <span class="token property">"user_metadata"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token property">"games.rewards_info"</span> <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">)</span>
</code></pre></div>
<ul>
<li><strong>Por defecto</strong> este tipo de índice omite el campo <code class="language-text">_id</code>, si queremos añadirlo solo tenemos que indicarlo dentro de <code class="language-text">wildcardProjection</code></li>
<li>No es posible crear indices compuestos usando wildcard</li>
<li>No pueden ser indices únicos ni tener TTL</li>
<li>No pueden ser Geoespaciales o Hashed</li>
<li>Si queremos ordenar con este tipo de índice solo podemos hacerlo usando el campo mediante el que busquemos, es decir, si usamos <code class="language-text">user_metadata.images</code> para buscar solo podremos hacer un sort en mongo usando ese campo.</li>
<li>No indexan campos vacios, es decir los ignoran y los guardan en el indice (son lo que se conoce como SPARSE)</li>
<li>No podemos hacer búsquedas haciendo coincidir un array al completo, solo campos sueltos</li>
<li>No podemos hacer búsquedas con un <code class="language-text">not equal null</code> porque no tiene esos elementos y no comprende que hacemos.</li>
</ul>
<h4 id="hashedindex">HASHED INDEX</h4>
<p>En estos índices lo que hace Mongo es convertir el valor del campo en un hash único y lo almacena. Este formato puede ser útil, en general para ahorrar espacio o para temas de <code class="language-text">sharding</code> (comprime los documentos hijos en un hash), ya que en lugar de almacenar el campo almacena un hash. Luego Mongo por si mismo hace su magia y cada vez que busques va convirtiendo el directamente el valor de los campos, es decir, nosotros no tenemos que hacer nada.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">alias</span><span class="token operator">:</span> <span class="token string">'hashed'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Importante:</p>
<ul>
<li><strong>No admiten búsquedas por rango solo exactas</strong></li>
<li><strong>No admiten coumpound index</strong></li>
</ul>
<h4 id="otrosindices">OTROS INDICES</h4>
<ul>
<li><strong>2D</strong>: Indices basados en coordenadas de planos 2d</li>
<li><strong>2Dsphere</strong>: Indices en formato Tierra, es decir, pone un plano en formato esfera para gestionar las coordenadas</li>
<li><strong>geoHaystack</strong>: Indices especializados en planos 2d de tamaño pequeño</li>
</ul>
<h3 id="propiedadesdelosindices">PROPIEDADES DE LOS INDICES</h3>
<ul>
<li><strong>TTL</strong>: Propiedad de single field index donde indicamos un tiempo de vida al índice para que elimine los documentos de la colección, util para colecciones de logs y cosas así. El valor que indiquemos no se puede cambiar, para cambiarlo tenemos que borrar el indice y crearlo de nuevo</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>eventlog<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">"lastModifiedDate"</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">expireAfterSeconds</span><span class="token operator">:</span> <span class="token number">3600</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p>También es posible indicar una hora de expiración si el propio campo es de tiempo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>log_events<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">"expireAt"</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">expireAfterSeconds</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p>Esto haría que este documento:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>log_events<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span> <span class="token punctuation">{</span>
<span class="token property">"expireAt"</span><span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token string">'July 22, 2013 14:00:00'</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token property">"logEvent"</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
<span class="token property">"logMessage"</span><span class="token operator">:</span> <span class="token string">"Success!"</span>
<span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p>Desapareciera a esa hora.</p>
<ul>
<li><strong>Unique</strong>: Campos o combinaciones de campos que no se pueden repetir</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>members<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">"user_id"</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">unique</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
db<span class="token punctuation">.</span>members<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">groupNumber</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">lastname</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">firstname</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">unique</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p>Este índice si no existe un campo lo guardará como null y no se podrá repetir</p>
<ul>
<li><strong>Partial Index</strong>: Podemos crear indices que solo esten referidos cuando se haga un tipo de filtro, es decir, que solo se indexará algo si el documento cumple con el filtro que se le indica, es decir, si creamos este índice:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>restaurants<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span>
<span class="token punctuation">{</span> <span class="token property">cuisine</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token property">name</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token property">partialFilterExpression</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">rating</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property"><span class="token keyword">$gt</span></span><span class="token operator">:</span> <span class="token number">5</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
<span class="token punctuation">)</span>
</code></pre></div>
<p>Solo indexará cuando <code class="language-text">rating</code> sea mayor que 5 (pero solo mayor que 5, no vale luego buscar por un mayor de 8), esto hace que consuma menos recursos el indice.</p>
<ul>
<li><strong>Case Insensitive</strong>: Podemos crear indices con case insensitive, indicando el <code class="language-text">locale</code> y el <code class="language-text">strength</code> que queremos que use para la parte insensitive</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>fruit<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">type</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span> <span class="token property">collation</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">locale</span><span class="token operator">:</span> <span class="token string">'en'</span><span class="token punctuation">,</span> <span class="token property">strength</span><span class="token operator">:</span> <span class="token number">2</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p>Para ver la diferencia en la comparación <a href="https://docs.mongodb.com/manual/reference/collation/#collation-document">Pulsa aquí</a></p>
<ul>
<li><strong>SPARSE INDEX</strong>: Con la opción sparse le indicamos que no guarde en el índice los documentos que no contengan el campo que le indicamos.</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>addresses<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">"xmpp_id"</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">sparse</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p>Tenemos que tener cuidado porque este tipo de indice puede no devolver todos los resultados, si usamos un filtro que contenga <code class="language-text">xmpp_id</code> nos ignorará los que no lo tengan y si buscamos también por otro campo no nos aparecerá</p>
<ul>
<li>
<p><strong>Index intersection</strong>: Intersección de índices, resumiendo esta funcionalidad, si mongo cree que funciona puede hacer uso de dos indices para hacer una búsqueda. Por poner un ejemplo, si tenemos dos single index uno con ciudad y otro con población, si buscamos por ambos puede mezclar los indices para mejorar la búsqueda, pero solo la búsqueda no lo usaria por ejemplo si buscamos por ciudad y luego queremos hacer un sort por población.</p>
</li>
<li>
<p><strong>background</strong>: Propiedad recomendada para que la colección no se bloquee mientras se rehacen los indices (aún así ojo con los campos que se tenga prevista un nivel alto de escritura)</p>
</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span>addresses<span class="token punctuation">.</span><span class="token function">createIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">"xmpp_id"</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">background</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<h3 id="trabajandoconindices">Trabajando con indices</h3>
<h4 id="verindicesdeunacoleccin">Ver indices de una colección</h4>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getIndexes</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Esto nos muestra algo similar a esto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb"><span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token property">"v"</span> <span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
<span class="token property">"key"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"_id"</span> <span class="token operator">:</span> <span class="token number">1</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"name"</span> <span class="token operator">:</span> <span class="token string">"_id_"</span><span class="token punctuation">,</span>
<span class="token property">"ns"</span> <span class="token operator">:</span> <span class="token string">"indexninja.index"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token property">"v"</span> <span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
<span class="token property">"key"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"_fts"</span> <span class="token operator">:</span> <span class="token string">"text"</span><span class="token punctuation">,</span>
<span class="token property">"_ftsx"</span> <span class="token operator">:</span> <span class="token number">1</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"name"</span> <span class="token operator">:</span> <span class="token string">"TextIndex"</span><span class="token punctuation">,</span>
<span class="token property">"ns"</span> <span class="token operator">:</span> <span class="token string">"indexninja.index"</span><span class="token punctuation">,</span>
<span class="token property">"weights"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"alias"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"bio"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token property">"firstName"</span> <span class="token operator">:</span> <span class="token number">10</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"default_language"</span> <span class="token operator">:</span> <span class="token string">"english"</span><span class="token punctuation">,</span>
<span class="token property">"language_override"</span> <span class="token operator">:</span> <span class="token string">"language"</span><span class="token punctuation">,</span>
<span class="token property">"textIndexVersion"</span> <span class="token operator">:</span> <span class="token number">3</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token property">"v"</span> <span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
<span class="token property">"key"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"lastName"</span> <span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1.0</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"name"</span> <span class="token operator">:</span> <span class="token string">"lastName_-1"</span><span class="token punctuation">,</span>
<span class="token property">"ns"</span> <span class="token operator">:</span> <span class="token string">"indexninja.index"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
</code></pre></div>
<p>Con la <code class="language-text">type_version</code> del indice, la <code class="language-text">key</code> por la que se ha realizado, el <code class="language-text">name</code> que tiene el indice y el <code class="language-text">ns</code>, es decir, la colección a la que pertenece</p>
<h4 id="eliminarunndice">Eliminar un índice</h4>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">dropIndex</span><span class="token punctuation">(</span><span class="token string">"lastName_-1"</span><span class="token punctuation">)</span>
db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">dropIndex</span><span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token property">lastName</span><span class="token operator">:</span> <span class="token operator">-</span><span class="token number">1</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span>
</code></pre></div>
<p>Esto nos devolvería algo similar a esto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb"><span class="token comment">/* 1 */</span>
<span class="token punctuation">{</span>
<span class="token property">"nIndexesWas"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"ok"</span> <span class="token operator">:</span> <span class="token number">1.0</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Donde nos índica el número de indices que coincidian con esa condición y el resultado</p>
<h4 id="eliminartodosovariosindices">Eliminar todos(o varios indices)</h4>
<p>Para eliminar todos los indices:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">dropIndexes</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Y a partir de la versión <strong>4.2</strong> de mongo podemos indicarle un array con los nombres de los indices que queremos eliminar</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">dropIndexes</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"TextIndex"</span><span class="token punctuation">,</span> <span class="token string">"lastName_-1"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</code></pre></div>
<h4 id="verelusoactualdelosindices">Ver el uso actual de los indices</h4>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">aggregate</span><span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property"><span class="token keyword">$indexStats</span></span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span>
</code></pre></div>
<p>Con esto podemos ver si se usan mucho o poco los indices actuales. Esto nos devuelve algo similar a esto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb"><span class="token comment">/* 1 */</span>
<span class="token punctuation">{</span>
<span class="token property">"name"</span> <span class="token operator">:</span> <span class="token string">"TextIndex"</span><span class="token punctuation">,</span>
<span class="token property">"key"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"_fts"</span> <span class="token operator">:</span> <span class="token string">"text"</span><span class="token punctuation">,</span>
<span class="token property">"_ftsx"</span> <span class="token operator">:</span> <span class="token number">1</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"host"</span> <span class="token operator">:</span> <span class="token string">"83165c61f9de:27017"</span><span class="token punctuation">,</span>
<span class="token property">"accesses"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"ops"</span> <span class="token operator">:</span> <span class="token builtin keyword">NumberLong</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token property">"since"</span> <span class="token operator">:</span> <span class="token builtin keyword">ISODate</span><span class="token punctuation">(</span><span class="token string">"2020-01-12T11:18:17.642Z"</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">/* 2 */</span>
<span class="token punctuation">{</span>
<span class="token property">"name"</span> <span class="token operator">:</span> <span class="token string">"_id_"</span><span class="token punctuation">,</span>
<span class="token property">"key"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"_id"</span> <span class="token operator">:</span> <span class="token number">1</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"host"</span> <span class="token operator">:</span> <span class="token string">"83165c61f9de:27017"</span><span class="token punctuation">,</span>
<span class="token property">"accesses"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"ops"</span> <span class="token operator">:</span> <span class="token builtin keyword">NumberLong</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token property">"since"</span> <span class="token operator">:</span> <span class="token builtin keyword">ISODate</span><span class="token punctuation">(</span><span class="token string">"2020-01-12T10:22:38.796Z"</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>También podemos ver que se ha usado en cada query que realizamos con el comando que estamos usando continuamente (además de mogollón de información relativa a la query)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span><span class="token string">'NinjaMaster@email.com'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"executionStats"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Y si por ejemplo queremos ver info extra cuando tenemos una busqueda con multiples condiciones, como un poco el orden de filtro que ha seguido con:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token property">city</span><span class="token operator">:</span> <span class="token string">'Madrid'</span><span class="token punctuation">,</span> <span class="token property">email</span><span class="token operator">:</span><span class="token string">'NinjaMaster@email.com'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">explain</span><span class="token punctuation">(</span><span class="token string">"allPlansExecution"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Esta query ademas de lo anterior nos devuelve:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token property">"allPlansExecution"</span> <span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token property">"nReturned"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"executionTimeMillisEstimate"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"totalKeysExamined"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"totalDocsExamined"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"executionStages"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"stage"</span> <span class="token operator">:</span> <span class="token string">"FETCH"</span><span class="token punctuation">,</span>
<span class="token property">"nReturned"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"executionTimeMillisEstimate"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"works"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"advanced"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"needTime"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"needYield"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"saveState"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"restoreState"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"isEOF"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token property">"docsExamined"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"alreadyHasObj"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"inputStage"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"stage"</span> <span class="token operator">:</span> <span class="token string">"IXSCAN"</span><span class="token punctuation">,</span>
<span class="token property">"nReturned"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"executionTimeMillisEstimate"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"works"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"advanced"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"needTime"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"needYield"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"saveState"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"restoreState"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"isEOF"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token property">"keyPattern"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"city"</span> <span class="token operator">:</span> <span class="token number">-1.0</span><span class="token punctuation">,</span>
<span class="token property">"email"</span> <span class="token operator">:</span> <span class="token number">1.0</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"indexName"</span> <span class="token operator">:</span> <span class="token string">"city_-1_email_1"</span><span class="token punctuation">,</span>
<span class="token property">"isMultiKey"</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token property">"multiKeyPaths"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"city"</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token property">"email"</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"isUnique"</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token property">"isSparse"</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token property">"isPartial"</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token property">"indexVersion"</span> <span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
<span class="token property">"direction"</span> <span class="token operator">:</span> <span class="token string">"forward"</span><span class="token punctuation">,</span>
<span class="token property">"indexBounds"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"city"</span> <span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">"[\"Madrid\", \"Madrid\"]"</span>
<span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token property">"email"</span> <span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">"[\"NinjaMaster@email.com\", \"NinjaMaster@email.com\"]"</span>
<span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"keysExamined"</span> <span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span>
<span class="token property">"seeks"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token property">"dupsTested"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"dupsDropped"</span> <span class="token operator">:</span> <span class="token number">0</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token property">"nReturned"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"executionTimeMillisEstimate"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"totalKeysExamined"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"totalDocsExamined"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"executionStages"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"stage"</span> <span class="token operator">:</span> <span class="token string">"FETCH"</span><span class="token punctuation">,</span>
<span class="token property">"filter"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"email"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"$eq"</span> <span class="token operator">:</span> <span class="token string">"NinjaMaster@email.com"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"nReturned"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"executionTimeMillisEstimate"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"works"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"advanced"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"needTime"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"needYield"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"saveState"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"restoreState"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"isEOF"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"docsExamined"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"alreadyHasObj"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"inputStage"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"stage"</span> <span class="token operator">:</span> <span class="token string">"IXSCAN"</span><span class="token punctuation">,</span>
<span class="token property">"nReturned"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"executionTimeMillisEstimate"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"works"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"advanced"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"needTime"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"needYield"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"saveState"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"restoreState"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"isEOF"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"keyPattern"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"city"</span> <span class="token operator">:</span> <span class="token number">-1.0</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"indexName"</span> <span class="token operator">:</span> <span class="token string">"city_-1"</span><span class="token punctuation">,</span>
<span class="token property">"isMultiKey"</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token property">"multiKeyPaths"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"city"</span> <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"isUnique"</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token property">"isSparse"</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token property">"isPartial"</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token property">"indexVersion"</span> <span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
<span class="token property">"direction"</span> <span class="token operator">:</span> <span class="token string">"forward"</span><span class="token punctuation">,</span>
<span class="token property">"indexBounds"</span> <span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"city"</span> <span class="token operator">:</span> <span class="token punctuation">[</span>
<span class="token string">"[\"Madrid\", \"Madrid\"]"</span>
<span class="token punctuation">]</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"keysExamined"</span> <span class="token operator">:</span> <span class="token number">6</span><span class="token punctuation">,</span>
<span class="token property">"seeks"</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
<span class="token property">"dupsTested"</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
<span class="token property">"dupsDropped"</span> <span class="token operator">:</span> <span class="token number">0</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">]</span>
</code></pre></div>
<h4 id="recomendablequelosndicesentrenenlaramasinosevitamostenerquetirardediscoparaconsultarlos">Recomendable que los índices entren en la RAM, asi nos evitamos tener que tirar de disco para consultarlos</h4>
<p>Para ver lo que ocupan los indices solo tenemos que lanzar el comando</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">totalIndexSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<p>El resultado está en <strong>bytes</strong></p>
<h4 id="vertodalainfoposibledeunacoleccin">Ver toda la info posible de una colección</h4>
<div class="kg-card kg-code-card gatsby-highlight" data-language="mongodb"><pre class="language-mongodb"><code class="language-mongodb">db<span class="token punctuation">.</span><span class="token function">getCollection</span><span class="token punctuation">(</span><span class="token string">'index'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">stats</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[JS Algoritmos y estructuras de datos II: Resolución de problemas. Patrón Frequency Counter]]></title><description><![CDATA[Antes de empezar a ver algoritmos complejos o las estructuras de datos entremos
un poco en el área de la resolución de problemas que, aunque no te lo creas,
existen algunos patrones típicos que podemos usar para resolver problemas y que
pueden ser bastante útiles en nuestro dia a dia o por lo menos a la hora de
hacer entrevistas. Aquí veremos algunos de estos patrones para que nos hagamos
una idea y luego simplemente sería ir buscando más. Empecemos.
Resolución de problemas
Antes de entrar a ve]]></description><link>https://jlgarcia.fulldev.ninja/js-algorithms-and-data-structures/</link><guid isPermaLink="false">Ghost__Post__5c1154572dd6610fd828cab0</guid><category><![CDATA[algoritmos]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 15 Jan 2019 17:48:01 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640.png" alt="JS Algoritmos y estructuras de datos II: Resolución de problemas. Patrón Frequency Counter"/><p>Antes de empezar a ver algoritmos complejos o las estructuras de datos entremos un poco en el área de la <strong>resolución de problemas</strong> que, aunque no te lo creas, existen algunos patrones típicos que podemos usar para resolver problemas y que pueden ser bastante útiles en nuestro dia a dia o por lo menos a la hora de hacer entrevistas. Aquí veremos algunos de estos patrones para que nos hagamos una idea y luego simplemente sería ir buscando más. Empecemos.</p>
<h2 id="resolucindeproblemas">Resolución de problemas</h2>
<p>Antes de entrar a ver patrones, vamos a comentar un poco algunos conceptos importantes.<br>
Empecemos por preguntarnos, ¿qué es un algoritmo?... Por ponerlo simple podemos definirlo <em>como un proceso o serie de pasos que tenemos que seguir para completar una tarea específica o para resolver un problema</em> (algo así podría valer ¿no?).<br>
Y esto ¿por qué es importante?... si lo pensamos detenidamente los desarrolladores realmente lo que hacemos es resolver problemas (muchos de estos los generamos nosotros mismos pero eso es otro tema) y aunque en nuestro día a día realmente puede que no necesitemos usar procesos complejos para nuestro trabajo, siempre estamos haciendo uso de algoritmos y como casi siempre en programación, alguien ya se ha encontrado con el problema que tenemos actualmente y puede ser que exista una manera mejor o más eficiente para resolver un problema en el que, por ejemplo, estemos usando bucles anidados o cosas similares (ya hemos visto que eso es kaka). Básicamente podemos entender que los algoritmos son como nuestras bases para ser mejores programadores y resolutores de problemas. También que aunque en vuestro dia a dia al final no hagáis uso de esto, siempre os podrá venir bien para las <strong>entrevistas</strong> o para las <strong>pruebas técnicas</strong>, que ahora cada vez más están recurriendo a este tipo de pruebas y muchas contienen problemas que podéis resolver con este tipo de patrones.</br></br></p>
<h3 id="bestpractices">Best Practices</h3>
<p>Como en la mayoría de entornos a la hora de resolver problemas tenemos unas <strong>best practices</strong> reconocidas (que realmente no usamos) y que podemos usarlas en última instancia si no somos capaces de resolver el problema que tenemos entre manos. Esto sería lo que llamaríamos <strong>Idear un plan de resolución de problemas</strong>, luego tenemos la otra opción que es <strong>dominar los patrones de resolución de problemas</strong> y aplicarlos directamente (ya llegaremos a esto demomoento empecemos con nuestro plan).</p>
<h4 id="pasosbsicospararesolverunproblema">Pasos básicos para resolver un problema</h4>
<p>Estos serían los pasos básicos que podemos seguir para resolver un problema:<br>
1. Entender realmente el problema<br>
2. Revisar ejemplos concretos de este problema<br>
3. Descomponer el problema en problemas más pequeños y asumibles<br>
4. Resolver o simplificar<br>
5. Revisar y refactorizar</br></br></br></br></br></p>
<p><strong>1. Entender el problema</strong><br>
Para ver si realmente entendemos el problema podemos hacernos algunas preguntas básicas:<br>
* ¿Puedo replantear el problema con mis propias palabras?<br>
* ¿Cuáles son realmente los inputs?<br>
* ¿Cuáles son los outputs que debería devolver la solución del problema?<br>
* ¿La salida puede ser determinada con los elementos que recibe el problema?¿Tenemos toda la información que necesitamos para resolver el problema?<br>
* ¿Como debo identificar los datos importantes que son parte del problema?</br></br></br></br></br></br></p>
<p>Lo primero seria resolver preguntas de este tipo para poder hacernos una idea de lo que necesitamos y donde tenemos las mayores dificultades con este problema.</p>
<p><strong>2. Buscar ejemplos</strong><br>
Si no tenemos ejemplos con la entrada y los resultados que deberíamos obtener, podemos tener tests o historias de usuario, pero al final, necesitamos algún tipo de pista de que es lo que necesitamos conseguir.<br>
A continuación podemos plantearnos empezar creando nosotros mismos ejemplos simples (podemos incluso simplificar un poco el problema ignorando algunas de sus condiciones) e ir avanzando añadiendo dificultad hasta tener toda la complejidad que el problema realmente tiene. OJO no se nos pueden olvidar ejemplos con entras vacías o erroneas.</br></br></p>
<p><strong>3. Descomponer el problema</strong><br>
En este punto debemos escribir los pasos que necesitamos tomar para resolver el problema, y sí <strong>escribir</strong> aunque parezca una tontería esto nos ayuda a plantear la resolución del problema correctamente viendo posibles fallos en nuestro planteamiento antes de escribir una sola línea de código. Al escribir los pasos, los estamos descomponiendo en otros más pequeños que son más sencillos de enfrentar.</br></p>
<p><strong>4. Resolver el problema/Simplificando el problema</strong><br>
Ahora llega el punto de realmente resolver el problema. A la hora de intentar resolverlo nos daremos cuenta donde realmente estará el núcleo de la difilcutad que tenemos para llegar a revolver el problema. En este punto lo que debemos hacer es ignorar esa dificultad, es decir, simplificamos el problema y lo resolvemos de esta manera. Una vez que esté resuelto volvemos a incorporar esa dificultad a nuestra solución.<br>
Aunque no lo parezca, este proceso ayuda muchas veces a resolver nuestro problema.</br></br></p>
<p><strong>5. Revisar y refactorizar</strong><br>
En este punto lo que tendríamos que hacer sería comprobar, lo primero, si nuestra solución realmente funciona en todos los casos y luego ya hacernos preguntas de este estilo:<br>
- ¿Podemos llegar a la misma solución de otra manera?<br>
- ¿Podemos usar este algoritmo para resolver otros problemas?<br>
- ¿Podemos mejorar el rendimiento de nuestra solución?<br>
- ¿Cómo han resuelto el problema otros desarrolladores?</br></br></br></br></br></p>
<p>Con un plan o estrategia similar a estos 5 puntos podemos acercarnos más a una solución a nuestro problema.</p>
<p>Y a continuación esta estrategia la complementaremos con nuestro conocimiento en algunos patrones típicos de resolución de problemas.</p>
<h3 id="commonproblemsolvingpatterns">Common problem solving patterns</h3>
<p>Existen multitud de patrones de resolución de problemas:<br>
- Frequency Counter<br>
- Multiple Pointers<br>
- Sliding Window<br>
- Divide and Conquer<br>
- Dynamic Programming<br>
- Greedy Algorithms<br>
- ....</br></br></br></br></br></br></br></p>
<p>Aquí comentaremos algunos que están en el nivel correcto sencillez/utilidad pero en esta página <a href="https://www.geeksforgeeks.org/fundamentals-of-algorithms/">GeeksForGeeks</a> tenemos todos los patrones o algoritmos que podamos necesitar (es muy completa).</p>
<p>Vamos a empezar viendo el que se conoce como <em>Frequency Counter</em></p>
<h3 id="patrnfrequencycounter">Patrón FREQUENCY COUNTER</h3>
<p>Este patrón es relativamente sencillo y tiene una función muy específica <em>"Contar las veces que algo se repite o aparece"</em>. En un primer momento podemos pensar en la utilidad de esto, veamoslo con un ejemplo.</p>
<p>Queremos un método que compruebe si un string es un <em>anagrama</em> de otro, es decir, queremos saber si ambos strings se pueden formar con las mismas letras. Una forma fácil es contar las veces que existe cada letra en ambos strings y comparar, veremos dos acercamientos posibles de este patrón</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">validAnagram</span><span class="token punctuation">(</span><span class="token parameter">string1<span class="token punctuation">,</span> string2</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token comment">//Comprobamos si el tamaño es el mismo,si no, terminamos antes de empezar</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>string1<span class="token punctuation">.</span>length <span class="token operator">!==</span> string2<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> frequency1 <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> frequency2 <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token comment">//Recorremos ambos strings y guardamos en un objeto siendo la letra la key y el valor el número de veces que aparece</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> char <span class="token keyword">of</span> string1<span class="token punctuation">)</span><span class="token punctuation">{</span>
frequency1<span class="token punctuation">[</span>char<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">++</span>frequency1<span class="token punctuation">[</span>char<span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> char <span class="token keyword">of</span> string2<span class="token punctuation">)</span><span class="token punctuation">{</span>
frequency2<span class="token punctuation">[</span>char<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">++</span>frequency2<span class="token punctuation">[</span>char<span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//Recorremos y comprobamos. Si en algún caso las cantidades no coinciden entonces no es un anagrama uno de otro</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> char <span class="token keyword">in</span> frequency1<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>frequency1<span class="token punctuation">[</span>char<span class="token punctuation">]</span> <span class="token operator">!==</span> frequency2<span class="token punctuation">[</span>char<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Esta es una solución válida, que excepto que tenemos 3 búcles for, no está mal. Veamos otro posible acercamiento en este caso son solo 2 búcles</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">validAnagram</span><span class="token punctuation">(</span><span class="token parameter">string1<span class="token punctuation">,</span> string2</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token comment">//Comprobamos si el tamaño es el mismo,si no, terminamos antes de empezar</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>string1<span class="token punctuation">.</span>length <span class="token operator">!==</span> string2<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">const</span> letters <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> string1<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
letters<span class="token punctuation">[</span>string1<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">++</span>letters<span class="token punctuation">[</span>string1<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> string2<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token comment">//Si es 0 o no existe no es un anagrama.</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>letters<span class="token punctuation">[</span>string2<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
letters<span class="token punctuation">[</span>string2<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">]</span> <span class="token operator">-=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>En este caso tenemos otra solución que tiene un búcle for menos y también nos funciona. Por si a alguien no le queda claro lo que estamos haciendo es restando las coincidencias del segundo string con el primero dentro de nuestro objeto letters y en el caso de que intentemos acceder a un valor que ya es 0 o que no exista es señal de que no es un anagrama.</p>
<p>Bueno y hasta aquí el patrón de <strong>Frequency Count</strong>, básicamente contamos dentro de un objeto CLAVE-VALOR los elementos que nos interesen, sencillo ¿verdad?</p>
<p>Nos vemos en el siguiente, un abrazooooooorrrrrrrr.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[JS Algoritmos y estructuras de datos I: Big O]]></title><description><![CDATA[Hablemos de algoritmos, eficiencia y esas cosas, es decir, hablemos de cosas
'chungas'.
Para medir la eficiencia de los algoritmos no usamos el tiempo propiamente dicho
(como podríamos pensar en un primer momento), si lo midiéramos mediante algo
temporal, como segundos, milisegundos o cosas así los datos no serían fiables,
ya que dependen del hardware y de lo que esté haciendo en ese momento el
ordenador.
En su lugar usamos 2 tipos de medidas:
* Time complexity (complejidad temporal).
* Space]]></description><link>https://jlgarcia.fulldev.ninja/js-algoritmos-y-estructuras-de-datos-big-o/</link><guid isPermaLink="false">Ghost__Post__5c1a01ea2dd6610fd828cad3</guid><category><![CDATA[algoritmos]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Sun, 04 Nov 2018 08:31:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e92df4805fb46ec1f6bec181d2305365/unordered-3192273_640.png" alt="JS Algoritmos y estructuras de datos I: Big O"/><p>Hablemos de algoritmos, eficiencia y esas cosas, es decir, hablemos de cosas 'chungas'.<br>
Para medir la eficiencia de los algoritmos no usamos el tiempo propiamente dicho (como podríamos pensar en un primer momento), si lo midiéramos mediante algo temporal, como segundos, milisegundos o cosas así los datos no serían fiables, ya que dependen del hardware y de lo que esté haciendo en ese momento el ordenador.<br>
En su lugar usamos 2 tipos de medidas:</br></br></p>
<ul>
<li><strong>Time complexity (complejidad temporal)</strong>.</li>
<li><strong>Space complexity (complejidad espacial)</strong> o también lo podríamos llamar <strong>Auxiliary Space complexity</strong> (luego hablaremos de esto).</li>
</ul>
<p>Y para cualquiera de estos tipos de medida usamos lo que se conoce como <strong>Big O notation</strong> o <strong>notación de Landau</strong>. No vamos a entrar en la matemática específica de esto, si queréis saber más tenéis más información <a href="https://es.wikipedia.org/wiki/Notaci%C3%B3n_de_Landau">aquí</a>. En nuestro caso valdrá con que tengamos este diagrama como referencia</p>
<p><img srcset="/assets/images/2018/12/Capture.JPG" alt="JS Algoritmos y estructuras de datos I: Big O"/></p>
<p>Siendo <strong>O(1)</strong> lo mejor y <strong>O(n^2)</strong> lo peor. Con esto como base empecemos.</p>
<h3 id="timecomplexity">TIME COMPLEXITY</h3>
<p>Al contrario de lo que indica su nombre no es una regla de medida temporal, lo que hace es medir la efeciencia basándose en el <strong>número de operaciones simples</strong> que realiza la función, entendiendo por operaciones simples: <strong>=, +, -, *, /, %, <, ></strong>.</p>
<p>Veamoslo mejor con algunos ejemplos simples:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">addUpTo</span><span class="token punctuation">(</span><span class="token parameter">n</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> total <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i<span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><=</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
total <span class="token operator">+=</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> total<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Veamos cuantas operaciones tenemos aquí:</p>
<ol>
<li><strong>let total=0</strong>: Primera asignación que ocurre solo 1 vez.</li>
<li><strong>let i=0</strong>: Segunda asignación que ocurre solo 1 vez.<br>
3 y 4. <strong>i <= n</strong>: Que se divide en 2 comparaciones 1 por el <strong><</strong> y otra por el <strong>=</strong> y esto se haría <strong>n</strong> veces.<br>
5 y 6. <strong>i++</strong>: Esto es una suma y una asignación a i que se produce a su vez <strong>n</strong> veces.<br>
7 y 8. <strong>total += i</strong>: Y esto es igual que el anterior una suma y una asignación que se produce <strong>n</strong> veces.</br></br></br></li>
</ol>
<p>En este caso tenemos <strong>2 operaciones simples que se producen solo 1 vez</strong> y luego <strong>6 operaciones que se producen n veces</strong>, es decir, que dependen de <strong>n</strong>, por lo tanto ¿cual creéis que será el <strong>TIME COMPLEXITY</strong> en este caso? Pensemos que son todo operaciones simples pero que dependen de <strong>n</strong>, por lo que en este caso nuestro valor será <strong>O(n)</strong>.</p>
<p>Vayamos ahora con otro ejemplo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">addUpToV2</span><span class="token punctuation">(</span><span class="token parameter">n</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> n <span class="token operator">*</span> <span class="token punctuation">(</span>n <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Es la misma función, es decir, hace lo mismo, nos devuelve la suma de todos los valores menores que n incluido n. Veamos las operaciones:</p>
<ol>
<li><strong>n+1</strong>: Operación suma que se produce 1 vez.</li>
<li><strong>n * (resultado de lo anterior)</strong>: Multiplicación del resultado anterior que se produce 1 vez.</li>
<li><strong>resultado anterior/2</strong>: División del resultado anterior que se produce solo 1 vez.</li>
</ol>
<p>En este caso tenemos solo 3 operaciones pero además estas operaciones <strong>solo se producen una vez</strong>, es decir, <strong>no dependen de n</strong>, por lo tanto, en este caso el valor sería O(1) puesto que pasemos el número que pasemos a n siempre es constante la cantidad de operaciones que se realizarán.</p>
<p>Otro ejemplo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">countUpAndDown</span><span class="token punctuation">(</span><span class="token parameter">n</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Hacia arriba..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"En la cima \n Bajando..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> j <span class="token operator">=</span> n <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> j <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">;</span> j<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>j<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Bajamos!!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>En este caso tenemos 2 bucles que como ya hemos visto cada una sería <strong>O(n)</strong>, es decir, <strong>O(2n)</strong>. Es <strong>2n</strong> porque depende 2 veces de n, pero al medir la complejidad siempre <strong>ignoramos los valores numéricos constantes</strong> por lo que volvemos a tener una función con un valor de <strong>0(n)</strong>.</p>
<p>Y ahora vamos con el último ejemplo con las medidas simples de medida (de momento no entramos a las medidas logarítmicas).</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">printAllPairs</span> <span class="token punctuation">(</span><span class="token parameter">n</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator"><</span> n<span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>i<span class="token punctuation">,</span>j<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Aquí tenemos otro par de bucles, pero en este caso son 2 bucles anidados, es decir, uno dentro de otro, por lo que sería un <strong>n</strong> veces del bucle interior, por cada <strong>n</strong> veces del bucle superior, es decir, <strong>n*n</strong> o <strong>n^2</strong>, resumiendo en este caso tendríamos la peor medida de todas <strong>O(n^2)</strong>.</p>
<p>Hasta aquí de momento en cuanto al <strong>Time Complexity</strong>, más adelante volveremos a ello, ahora vamos a por el <strong>Space Complexity</strong></p>
<h3 id="spacecomplexity">SPACE COMPLEXITY</h3>
<p>Cuando hablamos de la <strong>complejidad espacial</strong>, nos referimos a cuanta memoria necesitaremos para ejecutar nuestra función. Al igual que con la <strong>time complexity</strong>, se usa para medir <strong>O</strong>, lo único que en este caso lo que diferenciamos será:</p>
<ul>
<li><strong>Valores primitivos</strong>: number, boolean, undefined y null. Estos valores son siempre constantes en cuanto a su tamaño por lo que ocuparán <strong>O(1)</strong>.</li>
<li><strong>Objetos y arrays</strong>: Que en este caso se miden en O(n) siendo <strong>n la cantidad de keys en los objetos</strong> y <strong>siendo n el tamaño de array</strong>.</li>
</ul>
<p>En este caso la diferenciación es simple, si no tiene arrays u objetos será <strong>O(1)</strong>, si tiene n arrays u objetos <strong>O(n)</strong> y si tiene arrays u objetos anidados entre sí sería <strong>O(n^x)</strong> siendo <strong>x</strong> la cantidad de anidación que tengamos, es decir, si tenemos un array de 3 dimensiones tendremos un <strong>O(n^3)</strong>, si tenemos uno de 2 <strong>O(n^2)</strong>.</p>
<p>Esto en cuanto a la parte simple del <strong>space complexity</strong> y del <strong>time complexity</strong>, evidentemente todo esto tiene algo más de chicha cuando entramos en los resultados intermedios de la gráfica (si, esos que contienen logaritmos). Hagamos un repaso de los logaritmos</p>
<h3 id="logaritmos">LOGARITMOS</h3>
<p>Hablemos ahora de los logaritmos, puesto que aunque no los hayamos visto todavía en algún ejemplo si que forman parte de las mediciones de eficiencia de los algoritmos. Si os fijáis en la gráfica inicial están presentes en las mediciones intermedias.</p>
<p>Pues veamos, ¿qué es un logaritmo? Para ponerlo simple es lo contrario que un exponente, es decir, ¿cuál es el resultado de 2^4? (2 elevado a 4)?<br>
<strong>16</strong><br>
Por lo que entonces sería:<br>
<img srcset="/assets/images/2018/12/Capture-7.JPG" alt="JS Algoritmos y estructuras de datos I: Big O"/></br></br></br></p>
<p>Una definición más específica sería:<br>
Un logaritmo es la cantidad de veces que tengo que dividir un número por 2 (si es de base 2) hasta tener un valor menor o igual a 1. En nuestro caso serían <strong>4</strong> las veces que tenemos que dividir 16:</br></p>
<ol>
<li>16 / 2 = 8</li>
<li>8 / 2 = 4</li>
<li>4 / 2 = 2</li>
<li>2 / 2 = 1</li>
</ol>
<p>Y a la hora de hablar de logaritmos, por defecto siempre hablamos de logaritmos base 2, por lo que lo podemos omitir (y así es como lo vemos en las gráficas).</p>
<p>Bueno y hasta aquí lo básico, nos vemos en el siguiente, un abrazooorrrrr.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker IV: Development Workflow]]></title><description><![CDATA[La idea es ir empezando a ver como sería un entorno real de desarrollo con
Docker teniendo:
* Nuestro entorno de desarrollo: Un entorno donde creamos las cosas.
* Entorno de test: Tras el desarrollo, pasamos nuestro código al entorno de
test donde, como su propio nombre indica, probamos que todo funciona.
* Entorno de producción: Tras pasar los tests pertinentes automáticamente el
proyecto pasaría a producción.
Este workflow es lo que comunmente se conoce como Integración Continua,
Co]]></description><link>https://jlgarcia.fulldev.ninja/docker-iv-development-workflow/</link><guid isPermaLink="false">Ghost__Post__5be93e342dd6610fd828ca11</guid><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 01 Oct 2018 10:33:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8250fb6cd246dd294ed3fc4d99218f71/docker_facebook_share-3.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8250fb6cd246dd294ed3fc4d99218f71/docker_facebook_share-3.png" alt="Docker IV: Development Workflow"/><p>La idea es ir empezando a ver como sería un entorno real de desarrollo con Docker teniendo:</p>
<ul>
<li><strong>Nuestro entorno de desarrollo</strong>: Un entorno donde <em><strong>creamos</strong></em> las cosas.</li>
<li><strong>Entorno de test</strong>: Tras el desarrollo, pasamos nuestro código al entorno de test donde, como su propio nombre indica, probamos que todo funciona.</li>
<li><strong>Entorno de producción</strong>: Tras pasar los tests pertinentes automáticamente el proyecto pasaría a producción.</li>
</ul>
<p>Este <em>workflow</em> es lo que comunmente se conoce como <em>Integración Continua, Continuous Integration o CI</em>. Para este proceso usaremos herramientas o servicios como Github o Travis CI y desarrollaremos con ReactJS (no importa que no sepamos usarlos veremos lo necesario para entender lo que estamos haciendo).</p>
<h3 id="entornodedesarrollo">Entorno de desarrollo</h3>
<p>Empecemos por el primero de los entornos, el entorno de desarrollo. Lo que buscamos en este entorno es que nuestros cambios mientras estamos desarrollando se <em>sincronicen</em> automáticamente con el contenedor de desarrollo (esto en varios casos es innecesario pero lo veremos igualmente con los fines didácticos que nos ocupan).<br>
Pensando en el objetivo de este entorno, ya hemos visto que si realizamos cambios en nuestro código tenemos que volver a realizar un <em><strong>build</strong></em> y luego arrancar un contenedor nuevo con la imagen que nos crearía el build anterior. Esto realmente no es lo que estamos buscando, es poco eficiente y tendríamos demasiadas imágenes de contenedor.</br></p>
<p>En docker existe una forma de solucionar esto, vamos a introducir algo que no hemos visto todavia: <strong>Los Volúmenes</strong>.<br>
En docker un <em>volumen</em> no deja de ser una referencia al filesystem del contenedor y puede ser una referencia, como un <em>mapeo</em> (al igual que los puertos) de una carpeta local a una del contenedor, o un 'no lo toques' (que básicamente es mapea todo menos esto). Lo vamos a probar directamente, primero de todo vamos preparar un proyecto para trabajar con el, empecemos por crearnos un proyecto de ReactJS.</br></p>
<p>Para trabajar con react usaremos un paquete de npm que nos instala un proyecto básico inicial, lo instalamos con</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> -g <span class="token function">install</span> create-react-app
</code></pre></div>
<p>Una vez instalado ya podríamos crearnos un proyecto</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">create-react-app frontWeb
</code></pre></div>
<p>Esto nos creará un proyecto de react dentro de una carpeta llamada frontWeb. Para probar si funciona solo tenemos que entrar en la carpeta y ejecutar con:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> start
</code></pre></div>
<p><img srcset="/assets/images/2018/11/Capture.JPG" alt="Docker IV: Development Workflow"/></p>
<p>Bien ya tenemos nuestra web de react, vamos ahora con la parte del entorno de <em>desarrollo</em> de docker.<br>
Para ejecutar nuestro entorno de desarrollo en un contenedor solo necesitamos que tenga <strong>node</strong> instalado, es decir, que es similar a lo que hemos creado anteriormente.</br></p>
<p>Antes de continuar comentar que aunque vamos a trabajar casi todo el rato con comandos de <strong>docker-compose</strong> todo lo que hagamos a partir de ahora se puede hacer con comandos <strong>docker run</strong> también, pero realmente son comandos muy largos y poco útiles a la larga. En caso de necesidad siempre podemos buscar cual es el flag del comando para ponerlo directamente sin usar un <strong>dockerfile</strong>.</p>
<p>Continuemos, volvamos al principio, hemos dicho que queríamos un entorno de desarrollo donde nuestro contenedor se actualice automáticamente según vayamos haciendo cambios en local, para ello vamos a hacer uso de lo que en docker se conoce como <em>volumenes</em>.<br>
Lo primero nos crearemos dentro de nuestra carpeta de proyecto de react un fichero <em>dockerfile</em> pero esta vez pondremos:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">Dockerfile.dev
</code></pre></div>
<p>Como es normal aunque no lo hayamos visto a docker se le puede indicar el fichero <em>dockerfile</em> a usar cuando hacemos un build, solo tenemos que usar el flag <strong>-f</strong>, por ejemplo (ojo al punto del final)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker build -f ./Dockerfile.dev <span class="token builtin class-name">.</span>
</code></pre></div>
<p>Lo mismo con los ficheros para <strong>docker-compose</strong>, por lo que realmente no tendremos ningún problema y podemos tener varios <em>dockerfile</em> distintos según nuestro entorno.<br>
Sabiendo esto continuamos con nuestro fichero <strong>Dockerfile.dev</strong></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="docker"><pre class="language-docker"><code class="language-docker"><span class="token instruction"><span class="token keyword">FROM</span> node:alpine</span>
<span class="token instruction"><span class="token keyword">WORKDIR</span> <span class="token string">'/app'</span></span>
<span class="token instruction"><span class="token keyword">COPY</span> package.json .</span>
<span class="token instruction"><span class="token keyword">RUN</span> npm install</span>
<span class="token instruction"><span class="token keyword">COPY</span> . .</span>
<span class="token instruction"><span class="token keyword">CMD</span> [<span class="token string">"npm"</span>, <span class="token string">"start"</span>]</span>
</code></pre></div>
<p>Misma teoria que anteriormente, copiamos el package.json primero por posibles cambios solo del resto y no tener que hacer otra vez el <em>npm install</em> todo el rato cada vez que hagamos un build.<br>
Ya tenemos nuestro fichero <em>dockerfile</em>, ahora como la idea es usar <em>docker-compose</em> para todo necesitamos crear el fichero docker-compose.yml</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
<span class="token key atrule">web_react</span><span class="token punctuation">:</span>
<span class="token key atrule">build</span><span class="token punctuation">:</span>
<span class="token key atrule">context</span><span class="token punctuation">:</span> .
<span class="token key atrule">dockerfile</span><span class="token punctuation">:</span> Dockerfile.dev
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token string">"3000:3000"</span>
</code></pre></div>
<p>Antes de continuar, vemos que ahora donde tenemos puesto <em>build</em> ahora hemos añadido 2 propiedades:</p>
<ul>
<li><strong>context</strong>: Indicamos el contexto desde(path) desde el que trabajara el build del docker-compose.</li>
<li><strong>dockerfile</strong>: Nombre del fichero dockerfile que queremos usar.</li>
</ul>
<p>Continuemos, ahora vamos a hablar del concepto de <strong>Volume</strong> (por fin ;) ), primero añadamoslo al fichero</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
<span class="token key atrule">web_react</span><span class="token punctuation">:</span>
<span class="token key atrule">build</span><span class="token punctuation">:</span> ./Dockerfile.dev
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token string">"3000:3000"</span>
<span class="token key atrule">volumes</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> /app/node_modules
<span class="token punctuation">-</span> .<span class="token punctuation">:</span>/app
</code></pre></div>
<p>Si nos fijamos en lo que hemos puesto, tenemos realmente dos conceptos distintos dentro de <em>volumes</em>:</p>
<ul>
<li><strong>.:/app</strong>: Hablemos primero del segundo, este es similar al concepto de mapear puertos, básicamente le estamos indicando que <em>mapee</em> todo el contenido de la ruta actual de mi equipo local, al path <em>/app</em> del contenedor, lo que funcionaría similar a un acceso directo a los ficheros de la carpeta local de nuestro equipo.</li>
<li><strong>/app/node_modules</strong>: Si nos fijamos en esta línea no tenemos <strong>':'</strong>, eso es porque aquí le estamos indicando que haga como un <em>marcador</em> de la carpeta <em>node_modules</em> del contenedor, es decir, usa la del contenedor, no la toques y dejala donde está (esto hace que la carpeta se mantenga aunque hagamos el paso anterior).</li>
</ul>
<p>Ahora que ya sabemos lo que hemos puesto, viene la pregunta del ¿por qué?....bien, si pensamos en el proceso que hemos añadido en el <strong>Dockerfile.dev</strong>, tenemos una parte donde instalamos los paquetes que están indicados en el <em>package.json</em>, es decir, queremos que los descargues e instales de nuevo cuando hagamos un build de la imagen del contenedor, y no pasamos la carpeta local <em>node_modules</em> (que es donde instala las dependencias), que de hecho la vamos a eliminar para que veamos como funciona, si, <strong>eliminarla</strong>.</p>
<p>Ya que hablamos del <strong>Dockerfile.dev</strong>, alguno se puede preguntar si hacemos la refencia o linkado de nuestra carpeta local, ¿para qué hacemos el COPY?....bueno, esto es para prevenir creaciones para producción usando los mismos Dockerfiles, realmente en nuestro caso actual no lo necesitamos pero para producción siempre es mejor para evitar errores, ya que un contenedor en producción <strong>NO DEBE</strong> hacer referencias a carpetas locales de <strong>ningún sitio</strong> solo tiene que tener sus propios ficheros.</p>
<p>Ya tenemos todo ahora nos situamos en la ruta donde tenemos el fichero <em>docker-compose.yml</em> y ejecutamos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker-compose up
</code></pre></div>
<p>Si todo va bien deberíamos ver algo como esto en la consola<br>
<img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-14-a-las-9.35.40.png" alt="Docker IV: Development Workflow"/></br></p>
<p>Y si accedemos en el navegador a:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">localhost:3000
</code></pre></div>
<p>Deberíamos ver</p>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-14-a-las-9.37.02.png" alt="Docker IV: Development Workflow"/></p>
<p>Bien como tal ya tenemos todo funcionando, pero realmente lo que queremos es poder desarrollar en local y que se actualice el contenedor , ¿no?... pues vamos a probarlo.<br>
Nos vamos a nuestra web de react, y dentro de la carpeta <em>src</em> modificamos el fichero <em>App.js</em> y ponemos lo que queramos:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="html"><pre class="language-html"><code class="language-html"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>App<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>header</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>App-header<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span>{logo}</span> <span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>App-logo<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>logo<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>
Hola ninjaaaaasssss
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> //<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>--</span> <span class="token attr-name">Esta</span> <span class="token attr-name">es</span> <span class="token attr-name">la</span> <span class="token attr-name">linea</span> <span class="token attr-name">que</span> <span class="token attr-name">cambiamos</span>
<span class="token attr-name"><a</span>
<span class="token attr-name">className</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>App-link<span class="token punctuation">"</span></span>
<span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://reactjs.org<span class="token punctuation">"</span></span>
<span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span>
<span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>noopener noreferrer<span class="token punctuation">"</span></span>
<span class="token punctuation">></span></span>
Learn React
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>header</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span>
</code></pre></div>
<p>Y una vez que guardemos el documento automáticamente se debería actualizar el navegador y mostrar</p>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-14-a-las-9.40.32.png" alt="Docker IV: Development Workflow"/></p>
<p>¡¡¡PERFECTO!!!... ya tenemos nuestro entorno de desarrollo funcionando.</p>
<p>Empecemos con el entorno de <strong>TEST</strong></p>
<h4 id="test">TEST</h4>
<p>Por defecto react viene ya configurado con 1 test para poder probar, solo tenemos que hacer</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> run <span class="token builtin class-name">test</span>
</code></pre></div>
<p>o</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> <span class="token builtin class-name">test</span>
</code></pre></div>
<p>y automáticamente nos pasaría los tests</p>
<p><img srcset="/assets/images/2018/11/Capture-1.JPG" alt="Docker IV: Development Workflow"/></p>
<p>Bien, pues ahora queremos esto pero en un contenedor, como opción rápida podemos ejecutar una imagen creada con el mismo <em>dockerfile</em> pero cambiando el comando de arranque (esto es solo para que veais que funciona).</p>
<p>Por si no la tenemos creamos el build de la imagen, yo la voy a <em>taggear</em> para poder identificarla</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker build -f ./Dockerfile.dev <span class="token builtin class-name">.</span> -t test_react
</code></pre></div>
<p>Esto nos devuelve una imagen con ese nombre</p>
<p><img srcset="/assets/images/2018/11/Capture-2.JPG" alt="Docker IV: Development Workflow"/></p>
<p>Ya la tenemos, ahora solo vamos a realizar un <em>run</em> habitual cambiando el comando de arranque</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker run -it test_react <span class="token function">npm</span> <span class="token builtin class-name">test</span>
</code></pre></div>
<p>Le he añadido <em>-it</em> para poder trabajar con la consola de test y como algo nuevo si nos fijamos hemos puesto <em>cosas</em> tras el nombre de la imagen, básicamente todo lo que ponemos a continuación del nombre de la imagen a ejecutar lo toma como comando de arranque para el contenedor. Si lo ejecutamos nos devuelve<br>
<img srcset="/assets/images/2018/11/Capture-3.JPG" alt="Docker IV: Development Workflow"/></br></p>
<p>Otra opción es añadirlo a nuestro <em>docker-compose</em> añadiendo otro servicio pero con la misma teoría, compartiendo o <em>mapeando</em> ficheros entre el equipo local y el contenedor, teniendo 2 contenedores funcionando uno para las pruebas en desarrollo y otro probando los test. El problema de este acercamiento es que no tenemos control sobre la consola de test por lo que no podemos hacer mucho más que ver como pasan los tests cada vez que hacemos un cambio en los ficheros.<br>
Vamos a probarlo, cambiamos nuestro fichero <em>docker-compose</em></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
<span class="token key atrule">web_react</span><span class="token punctuation">:</span>
<span class="token key atrule">build</span><span class="token punctuation">:</span>
<span class="token key atrule">context</span><span class="token punctuation">:</span> .
<span class="token key atrule">dockerfile</span><span class="token punctuation">:</span> Dockerfile.dev
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token string">"3000:3000"</span>
<span class="token key atrule">volumes</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> /app/node_modules
<span class="token punctuation">-</span> .<span class="token punctuation">:</span>/app
<span class="token key atrule">test_react</span><span class="token punctuation">:</span>
<span class="token key atrule">build</span><span class="token punctuation">:</span>
<span class="token key atrule">context</span><span class="token punctuation">:</span> .
<span class="token key atrule">dockerfile</span><span class="token punctuation">:</span> Dockerfile.dev
<span class="token key atrule">volumes</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> /app/node_modules
<span class="token punctuation">-</span> .<span class="token punctuation">:</span>/app
<span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"npm"</span><span class="token punctuation">,</span><span class="token string">"test"</span><span class="token punctuation">]</span>
</code></pre></div>
<p>Como véis hemos añadido otro servicio (contenedor ya sabéis), en este caso se llama <strong>test_react</strong>, que usa el mismo <em>dockerfile</em> y mapea de la misma forma los <em>volumenes</em>. Despues de eso si que tiene cambios, hemos quitado el <em>mapeo</em> del puerto porque ya no lo necesitamos y como extra nuevo hemos añadido la propiedad <strong>command</strong> que básicamente lo que hace es cambiar el comando de inicio del contenedor.<br>
A continuación si ejecutamos nuestro <em>docker-compose up</em>, nos crea dos contenedores y como podremos ver el log ambos funcionan correctamente, y si cambiamos algo en los ficheros se actualizan ambos, tanto el de desarrollo como el que pasa los tests.</br></p>
<p><img srcset="/assets/images/2018/11/Capture-4.JPG" alt="Docker IV: Development Workflow"/></p>
<p>Ninguno de los casos es muy <strong>ideal</strong> pero son funcionales y puede que en algún caso nos pueda servir para algo, más adelante veremos un entorno de test más 'real' por el momento esto es más que suficiente, a continuación empezaremos a hablar un poco de <strong>PRODUCCIÓN</strong></p>
<h4 id="produccin">PRODUCCIÓN</h4>
<p>Pasemos ahora a <em>producción</em>, la intención es crear un contenedor que nos devuelva nuestra aplicación ya preparada para producción, para el que no lo sepa, una app de react la preparamos para producción ejecutando el comando:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell"><span class="token function">npm</span> run build
</code></pre></div>
<p>Y este comando nos deja unos ficheros típicos de web (html, js y css), es decir, <em>ficheros estáticos</em>. Estos ficheros los deja en una carpeta llamada <strong>build</strong> dentro de nuestro proyecto.</p>
<p>Ahora necesitamos para producción un <em>servidor web</em>, los más utilizados son <strong>Apache o Nginx</strong>, aunque podríamos hacerlo con NodeJS, Go, Ruby, etc..... con casi todos los lenguajes tenemos alguna opción para hacerlo. En nuestro caso usaremos un contenedor con Nginx.</p>
<p>Si miramos la documentación del <a href="https://hub.docker.com/_/nginx/">contenedor oficial</a> podemos ver que los ficheros los sirve desde el path <strong>/usr/share/nginx/html</strong>. Sabiendo esto entonces básicamente lo que tendriamos que hacer sería copiar nuestros ficheros de producción en esa ruta del contenedor de nginx... pero claro se supone que no tenemos en local los archivos, veamos como podemos hacerlo con el entorno que tenemos ahora.</p>
<p>Nos vamos a crear un nuevo <strong>dockerfile</strong> con esto</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="docker"><pre class="language-docker"><code class="language-docker"><span class="token instruction"><span class="token keyword">FROM</span> node:alpine <span class="token keyword">as</span> builder</span>
<span class="token instruction"><span class="token keyword">WORKDIR</span> <span class="token string">'/app'</span></span>
<span class="token instruction"><span class="token keyword">COPY</span> package.json .</span>
<span class="token instruction"><span class="token keyword">RUN</span> npm install</span>
<span class="token instruction"><span class="token keyword">COPY</span> . .</span>
<span class="token instruction"><span class="token keyword">RUN</span> npm run build</span>
<span class="token instruction"><span class="token keyword">FROM</span> nginx</span>
<span class="token instruction"><span class="token keyword">COPY</span> <span class="token options"><span class="token property">--from</span><span class="token punctuation">=</span><span class="token string">builder</span></span> /app/build /usr/share/nginx/html</span>
</code></pre></div>
<p>Empecemos por la primera linea:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">FROM node:alpine as builder
</code></pre></div>
<p>Introducimos algo nuevo en este punto, básicamente lo que estamos haciendo es indicarle al proceso que añada como una referencia al resultado del <em>build</em> de ese contenedor con nombre <em>builder</em>, pero puede ser cualquier otro. Esta referencia solo está disponible en el contexto de la ejecución de <em>docker build</em>.<br>
El resto del primer contenedor es algo que ya hemos visto, vayamos con el segundo</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="docker"><pre class="language-docker"><code class="language-docker"><span class="token instruction"><span class="token keyword">FROM</span> nginx</span>
<span class="token instruction"><span class="token keyword">COPY</span> <span class="token options"><span class="token property">--from</span><span class="token punctuation">=</span><span class="token string">builder</span></span> /app/build /usr/share/nginx/html</span>
</code></pre></div>
<p>Aquí empezamos con el segundo contenedor. Vemos como la instrucción COPY tiene algo nuevo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="docker"><pre class="language-docker"><code class="language-docker">--from=builder
</code></pre></div>
<p>Como os podéis imaginar tiene que ver con la instrucción <em>as builder</em> del primer contenedor, aquí le estamos diciendo que del primer contenedor se copie la ruta <em>/app/build</em> y la pegue en <em>/usr/share/nginx/html</em><br>
Bien pues vamos a ejecutar nuestro nuevo build</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker build <span class="token builtin class-name">.</span>
</code></pre></div>
<p>Una vez terminado</p>
<p><img srcset="/assets/images/2018/11/Capture-5.JPG" alt="Docker IV: Development Workflow"/></p>
<p>Tenemos ya construido una imagen con supuestamente <strong>nginx</strong> y nuestra app en producción. Por último nos faltaría crear un contenedor con esa imagen, pues vamos a ello</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker run -p <span class="token number">3500</span>:80 --name webpro idImagen
</code></pre></div>
<p>Como extra he añadido <strong>--name</strong> que lo que hace es <em>taggearnos</em> el contenedor con un nombre que podamos gestionar de manera más comoda que un ID numérico</p>
<p><img srcset="/assets/images/2018/11/Capture-6.JPG" alt="Docker IV: Development Workflow"/></p>
<p>Se puede ver al principio el comando y a continuación un log (el de nginx) una vez que intentamos acceder a la página</p>
<p><img srcset="/assets/images/2018/11/Capture2.JPG" alt="Docker IV: Development Workflow"/></p>
<p>Y como podemos ver ya tenemos nuestro entorno para producción que básicamente es el build del <em>dockerfile</em> una vez que hemos terminado de desarrollar.</p>
<p>En próximos posts veremos una forma más profesional de hacer todo esto con <em>Integración Continua</em> gracias a <strong>TravisCI</strong> y <strong>GitHub</strong>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker III: Más complicado]]></title><description><![CDATA[Empecemos con cosas más complicadas, ahora vamos a preparar un entorno que se
comunique entre sí y en el que podamos crear varios contenedores que se
comuniquen entre con un solo comando.
Para poder hacer esto, empezaremos a ver algo que se llama docker-compose, esto
son otra serie de comandos pertenecientes al entorno de Docker, en el que
básicamente se busca un fichero docker-compose.yml con las instrucciones que se
deben seguir.
Lo primero, en nuestra carpeta visits donde hemos creado anterio]]></description><link>https://jlgarcia.fulldev.ninja/docker-iii-mas-complicado/</link><guid isPermaLink="false">Ghost__Post__5be6b01a2dd6610fd828ca02</guid><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Sat, 01 Sep 2018 10:32:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8250fb6cd246dd294ed3fc4d99218f71/docker_facebook_share-2.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8250fb6cd246dd294ed3fc4d99218f71/docker_facebook_share-2.png" alt="Docker III: Más complicado"/><p>Empecemos con cosas más complicadas, ahora vamos a preparar un entorno que se comunique entre sí y en el que podamos crear varios contenedores que se comuniquen entre con un solo comando.<br>
Para poder hacer esto, empezaremos a ver algo que se llama <strong>docker-compose</strong>, esto son otra serie de comandos pertenecientes al entorno de Docker, en el que básicamente se busca un fichero <strong>docker-compose.yml</strong> con las instrucciones que se deben seguir.<br>
Lo primero, en nuestra carpeta <strong>visits</strong> donde hemos creado anteriormente nuestro <strong>dockerfile</strong> con nuestra aplicación en NodeJS, nos creamos el fichero <strong>docker-compose.yml</strong> y vayamos poco a poco</br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
</code></pre></div>
<ul>
<li><strong>version</strong>: Hace referencia a la versión de la <em><strong>composición</strong></em>, esto le indica a docker, cuando ejecutamos comandos del CLI de docker-compose, si es versión más actual de <strong>docker-compose</strong> (a fecha de este texto es la 3).</li>
<li><strong>services</strong>: Dentro del fichero, la propiedad services hace referencia a los contenedores, no a un servicios, dentro de este apartado indicaremos todos los contenedores que crearemos mediante esta <em><strong>composición</strong></em>.</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
<span class="token key atrule">redis-server</span><span class="token punctuation">:</span>
<span class="token key atrule">image</span><span class="token punctuation">:</span> <span class="token string">'redis'</span>
<span class="token key atrule">node-app</span><span class="token punctuation">:</span>
<span class="token key atrule">build</span><span class="token punctuation">:</span> .
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token string">"4001:8081"</span>
</code></pre></div>
<p>Dentro del apartado de services hemos indicado 2 contenedores: <strong>redis-server</strong> y <strong>node-app</strong>. Un detalle importante antes de continuar: <strong>TODOS LOS CONTENEDORES DENTRO DEL MISMO DOCKER-COMPOSE ESTÁN DENTRO DE LA MISMA RED</strong>, es decir, tienen comunicación entre ellos, y una forma de llamarse unos a otros es <strong>con el propio nombre que hemos indicado en el fichero de docker-compose.yml</strong>, por lo que si volvemos a nuestro fichero <em>index.js</em> donde tenemos nuestra aplicación de NodeJS, tenemos que hacer un pequeño cambio que antes habíamos ignorado, cuando creamos nuestro cliente de redis es necesario indicarle el host y el puerto del servidor que tiene el servicio de <strong>redis-server</strong> (siempre es necesario indicarlo menos cuando está en el mismo servidor que el cliente). Para indicarlo en este caso solo es necesario con:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> client <span class="token operator">=</span> redis<span class="token punctuation">.</span><span class="token function">createClient</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
host<span class="token operator">:</span> <span class="token string">'redis-server'</span><span class="token punctuation">,</span>
port<span class="token operator">:</span> <span class="token number">6379</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>Si nos fijamos hemos puesto el mismo nombre que en nuestro <strong>docker-compose</strong>, realmente lo que esta sucediendo es que cuando la petición llega a la <em>red interna de docker</em> el está reconociendo el nombre y sabe donde ir a buscarlo.<br>
Sabiendo esto y ya teniendo el cambio continuemos con nuestro <strong>docker-compose.yml</strong>, teniamos esto:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
<span class="token key atrule">redis-server</span><span class="token punctuation">:</span>
<span class="token key atrule">image</span><span class="token punctuation">:</span> <span class="token string">'redis'</span>
<span class="token key atrule">node-app</span><span class="token punctuation">:</span>
<span class="token key atrule">build</span><span class="token punctuation">:</span> .
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token string">"4001:8081"</span>
</code></pre></div>
<p>Siguiendo con lo que nos faltaba:</p>
<ul>
<li><strong>image</strong>: Básicamente le estamos indicando que ese contenedor use la imagen de contenedor con nombre <em>redis</em> (ya sea nuestra o de la <em>docker store</em>)</li>
<li><strong>build</strong>: Le indicamos que inicie el proceso de <strong>build</strong> con el fichero <strong>dockerfile</strong> que se encuentra en la ruta indicada.</li>
<li><strong>ports:</strong> Puertos a <em>mapear</em> en este contenedor de nuestro equipo local.</li>
</ul>
<p>Con esto ya tendríamos todo listo para que nuestro conjunto de contenedores funcionaran, vamos a probarlos. Para ello basta con ejecutar:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker-compose up
</code></pre></div>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-12-a-las-9.13.39.png" alt="Docker III: Más complicado"/></p>
<p>Como vemos tenemos los dos contenedores levantados con los nombres que le hemos indicado en el fichero <strong>docker-compose.yml</strong>. Si ahora accedemos a <strong>localhost:4001</strong> (recordad que hemos cambiado el puerto al hacer el mapeo)</p>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-12-a-las-9.17.06.png" alt="Docker III: Más complicado"/></p>
<p>Vemos como funciona perfectamente.</p>
<h3 id="comandosdockercompose">Comandos docker-compose</h3>
<p>Veamos algunos comandos de <strong>docker-compose</strong>:</p>
<ul>
<li><strong>docker-compose up</strong>: Funciona como <strong>docker run</strong>, busca el fichero <em><strong>docker-compose up</strong></em> y ejecuta lo que aparece en el.</li>
<li><strong>docker-compose up --build</strong>: Fuerza a rehacer los contenedores antes de ejecutarlos. Muy útil si hemos realizado algún cambio en nuestro código de aplicación.</li>
<li><strong>docker-compose up -d</strong>: Arranca los contenedores en segundo plano.</li>
<li><strong>docker-compose down</strong>: Para los contenedores y elimina tanto los contenedores como la red que crea entre ellos.</li>
<li><strong>docker-compose start</strong>: Arranca los contenedores si están parados (OJO parados que no eliminados)</li>
<li><strong>docker-compose stop</strong>: Para los contenedores y <strong>NO</strong> elimina nada.</li>
<li><strong>docker-compose ps</strong>: Al igual que docker ps, vemos el estado de nuestra <em><strong>composición</strong></em> de contenedores.</li>
</ul>
<p><strong>TODOS LOS COMANDOS DE DOCKER COMPOSE NECESITAN EL FICHERO DE docker-compose.yml PARA FUNCIONAR</strong></p>
<h3 id="reinicioautomticodecontenedores">Reinicio automático de contenedores</h3>
<p>Puede pasar que alguno de nuestros contenedores se detenga, por algún error por ejemplo, en este caso docker ya está preparado para automáticamente reiniciar los contenedores según como lo configuremos en nuestro docker-compose.yml. Tenemos estas opciones de reinicio:</p>
<ul>
<li><strong>"no"</strong>: Es la configuración por defecto de los contenedores. No se reinician en ningún caso. Para poner explicitamente <em><strong>no</strong></em> es necesario ponerlo entre ""</li>
<li><strong>always</strong>: Siempre que se pare, sea cual sea la razón, automáticamente se reinicia.</li>
<li><strong>on-failure</strong>: Solo se reinicia cuando se pare con un <em><strong>error code</strong></em>. En general si el código de salida ha sido un 0, eso significa que se ha parado de manera controlada o porque ha terminado su ejecución correctamente, sin embargo, si el código con el termina es distinto de 0 entonces lo tomará como un error y reiniciará el contenedor.</li>
<li><strong>unless-stopped</strong>: Siempre se reinicia a menos que lo hayamos parado nosotros manualmente.</li>
</ul>
<p>Para configurar estas opciones solo tenemos que indicarselo en el fichero de la siguiente forma:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="yaml"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">'3'</span>
<span class="token key atrule">services</span><span class="token punctuation">:</span>
<span class="token key atrule">redis-server</span><span class="token punctuation">:</span>
<span class="token key atrule">image</span><span class="token punctuation">:</span> <span class="token string">'redis'</span>
<span class="token key atrule">node-app</span><span class="token punctuation">:</span>
<span class="token key atrule">restart</span><span class="token punctuation">:</span> always <<span class="token punctuation">-</span><span class="token punctuation">-</span>Con esta opción
<span class="token key atrule">build</span><span class="token punctuation">:</span> .
<span class="token key atrule">ports</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> <span class="token string">"4001:8081"</span>
</code></pre></div>
<p>Esto último era un extra que nos puede ser útil a la hora de configurar nuestro contenedor. Nos vemos en el siguienteeee, un abrazooor.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker II: Creando contenedores]]></title><description><![CDATA[Ahora vamos a empezar a trabajar con lo que se conoce como Dockerfile, que
básicamente es un fichero con la configuración que queremos para un contenedor.
Lo primero nos creamos un fichero llamado Dockerfile(sin extension)
# Indicamos una imagen base de la que partir. Usamos alpine que es una básica sin prácticamente nada
FROM alpine
#Descargamos e instalamos las dependencias que queramos. Usamos el copando apk que es un gestor de paquetes que viene dentro de la imagen de alpine
RUN apk add -]]></description><link>https://jlgarcia.fulldev.ninja/docker-ii-creando-contenedores/</link><guid isPermaLink="false">Ghost__Post__5be1df0c2dd6610fd828c9ed</guid><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Wed, 01 Aug 2018 10:32:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8250fb6cd246dd294ed3fc4d99218f71/docker_facebook_share-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8250fb6cd246dd294ed3fc4d99218f71/docker_facebook_share-1.png" alt="Docker II: Creando contenedores"/><p>Ahora vamos a empezar a trabajar con lo que se conoce como <strong>Dockerfile</strong>, que básicamente es un fichero con la configuración que queremos para un contenedor.</p>
<p>Lo primero nos creamos un fichero llamado <strong>Dockerfile</strong>(sin extension)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="docker"><pre class="language-docker"><code class="language-docker"><span class="token comment"># Indicamos una imagen base de la que partir. Usamos alpine que es una básica sin prácticamente nada</span>
<span class="token instruction"><span class="token keyword">FROM</span> alpine</span>
<span class="token comment">#Descargamos e instalamos las dependencias que queramos. Usamos el copando apk que es un gestor de paquetes que viene dentro de la imagen de alpine</span>
<span class="token instruction"><span class="token keyword">RUN</span> apk add --update redis</span>
<span class="token comment"># Le indicamos a la imagen que hacer o que comandos ejecutar cuando arranque</span>
<span class="token instruction"><span class="token keyword">CMD</span> [<span class="token string">"redis-server"</span>]</span>
</code></pre></div>
<p>Nos situamos en la consola (o linea de comandos), en la carpeta donde tenemos el fichero y ejecutamos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker build <span class="token builtin class-name">.</span>
</code></pre></div>
<p>Esto nos ejecuta los comandos que tiene nuestro fichero. Para que entendamos el proceso, si miramos detenidamente el log de salida del comando veremos como en cada paso nos genera una imagen intermedia, ejecuta el comando del paso que le toque crea un <strong>snapshot</strong> para el siguiente paso y elimina la imagen anterior<br>
<img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-07-a-las-9.29.37.png" alt="Docker II: Creando contenedores"/></br></p>
<p>Por último vemos que nos pone <strong>Successfully build .....</strong>, ese ID que nos aparece seria el nombre de nuestra imagen creada, a continuación solo tenemos que ejecutar</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker run IDimagen
</code></pre></div>
<p>Y veremos como se ejecuta perfectamente nuestro contenedor<br>
<img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-07-a-las-9.32.26.png" alt="Docker II: Creando contenedores"/></br></p>
<p>Y si miramos que se esta ejecutando, veremos un nuevo contenedor con un nombre aleatorio que parte de nuestra imagen anteriormente creada<br>
<img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-07-a-las-9.37.28.png" alt="Docker II: Creando contenedores"/></br></p>
<h3 id="usandolacach">Usando la Caché</h3>
<p>Si rehusamos un <strong>Dockerfile</strong> o creamo uno nuevo igual que otro o con los mismo pasos iniciales, Docker usará su caché para no tener que repetir procesos que ya ha ejecutado, veamoslo con un ejemplo. Si añadimos otra dependencia a la instalación:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="docker"><pre class="language-docker"><code class="language-docker"><span class="token instruction"><span class="token keyword">FROM</span> alpine</span>
<span class="token instruction"><span class="token keyword">RUN</span> apk add --update redis</span>
<span class="token instruction"><span class="token keyword">RUN</span> apk add --update gcc</span>
<span class="token instruction"><span class="token keyword">RUN</span> apk add --update vim</span>
<span class="token instruction"><span class="token keyword">CMD</span> [<span class="token string">"redis-server"</span>]</span>
</code></pre></div>
<p>Y ejecutamos de nuevo el comando <strong>build</strong>, veremos como en los pasos iniciales nos sale <strong>Using cache</strong>, en algunas lineas, concretamente en las que se han repetido. <strong>OJO solo aparece hasta que llega a la línea que ha cambiado del Dockerfile</strong>, una vez que encuentra algo distinto ya lo hace todo de nuevo (si cambiaramos el orden de los comandos RUN lo haría todo de nuevo)</p>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-07-a-las-9.56.09.png" alt="Docker II: Creando contenedores"/></p>
<h3 id="aadirtagaimagen">Añadir TAG a imagen</h3>
<p>Si nos fijamos cuando se termina de construir la imagen de nuestro contenedor, nos pone un ID cualquiera, algo que es dificil de recordar. Es posible indicarle un nombre identificativo a nuestro contenedor, para ello basta con:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker build -t aliasDockerHub/nombreImagen:latest <span class="token builtin class-name">.</span>
</code></pre></div>
<p>Con el flag <strong>t</strong> indicamos que queremos <strong>taggear</strong> la imagen creada con un nombre, el cual es necesario que tenga la estructura que veis con el alias que tenemos en el marketplace de <strong>DockerHub</strong></p>
<h3 id="crearimagenapartirdeuncontenedorexistente">Crear Imagen a partir de un contenedor existente</h3>
<p>La idea es configurar un contenedor como queramos y luego generar una imagen de ese contenedor para poder desplegarla. <strong>Es necesario indicarle cual el es comando de inicio</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker commit -c <span class="token string">'CMD["redis-server"]'</span> idContenedor
</code></pre></div>
<p>Con este comando generaríamos una imagen que arrancaría con el comando <strong>redis-server</strong>. Este nos genera una imagen con un id gigantesco, pero para usarla no tenemos que copiar todo el id con una parte inicial que sea única y ya docker la busca.</p>
<h3 id="creandoimagenpropia20">Creando imagen propia 2.0</h3>
<p>Hasta ahora hemos visto como crear una imagen usando otra como base e instalando algún paquete extra, pero....y ¿si queremos añadir algún desarrollo o fichero nuestro? Vamos a crear una mini aplicación en <strong>NodeJS</strong> que nos devuelva una página. Para ello vamos a crearnos una nueva carpeta para almacenar todos los ficheros de este contenedor, por ejemplo la llamaremos <strong>miniapp</strong>.<br>
Dentro de esta carpeta lo primero nos creamos un fichero <strong>package.json</strong> que contendrá las dependencias y scripts de nuestro aplicación en NodeJS (quién no sepa de que estamos hablando puede revisarse los post de NodeJS donde lo explico todo con más detalle). Dentro de este fichero ponemos:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="json"><pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
<span class="token property">"dependencies"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"express"</span><span class="token operator">:</span> <span class="token string">"*"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
<span class="token property">"start"</span><span class="token operator">:</span> <span class="token string">"node index.js"</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Aquí le estamos diciendo que tenemos como dependencias cualquier versión de express y un script de npm para arrancar el fichero <strong>index.js</strong>.<br>
Ahora como os podéis imaginar tenemos que crear ese fichero, el <strong>index.js</strong></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="javascript"><pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
res<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token string">'How are you doing'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">8080</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Listening on port 8080'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>Ya tenemos nuestro proyecto de node preparado, ahora vamos a crear nuestro fichero <strong>Dockerfile</strong> para indicarle los pasos necesarios</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="docker"><pre class="language-docker"><code class="language-docker"><span class="token comment">#Imagen de la que partimos. En este caso usamos una imagen de node en su versión alpine (es decir con lo mínimo posible)</span>
<span class="token instruction"><span class="token keyword">FROM</span> node:alpine</span>
<span class="token comment">#Comando nuevo. Con este comando copiamos los ficheros de un origen en nuestro equipo local a una ruta en el contenedor</span>
<span class="token instruction"><span class="token keyword">COPY</span> ./ ./</span>
<span class="token comment">#Ejecutamos la instalación de las dependencias que hemos indicado en el package.json</span>
<span class="token instruction"><span class="token keyword">RUN</span> npm install</span>
<span class="token comment"># Le indicamos como comando de arranque el script que hemos indicado en el package.json que básicamente inicia nuestra aplicación en Node</span>
<span class="token instruction"><span class="token keyword">CMD</span> [<span class="token string">"npm"</span>,<span class="token string">"start"</span>]</span>
</code></pre></div>
<p>Ahora tenemos como comando nuevo <strong>COPY</strong> este comando copia contenido de una carpeta local (relativa a la ejecución del comando de docker build) a una carpeta en el propio contenedor.</p>
<h3 id="cambiandoeldirectoriodeejecucinenelcontenedor">Cambiando el directorio de ejecución en el contenedor</h3>
<p>Con la configuración anterior, en el contenedor anterior todo se copia y se ejecuta en la raiz (/), eso en linux <strong>NO ESTÁ BIEEEEN</strong>, tenemos que indicarle un directorio en condiciones a nuestra aplicación o a nuestro ficheros. Para ello tenemos el comando <strong>WORKDIR</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="docker"><pre class="language-docker"><code class="language-docker"><span class="token instruction"><span class="token keyword">WORKDIR</span> pathDondeTrabajar</span>
</code></pre></div>
<p>Básicamente cambia el path desde el que se está trabajando en el Dockerfile, una ruta posible para usar puede ser dentro de <strong>/usr/app</strong> (si no existe, nos crea la carpeta), por lo que quedaría así nuestro Dockerfile</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="docker"><pre class="language-docker"><code class="language-docker"><span class="token comment">#Imagen de la que partimos. En este caso usamos una imagen de node en su versión alpine (es decir con lo mínimo posible)</span>
<span class="token instruction"><span class="token keyword">FROM</span> node:alpine</span>
<span class="token comment"># Directorio desde el que funcionarian las siguientes instrucciones</span>
<span class="token instruction"><span class="token keyword">WORKDIR</span> /usr/app</span>
<span class="token comment">#Comando nuevo. Con este comando copiamos los ficheros de un origen en nuestro equipo local a una ruta en el contenedor</span>
<span class="token instruction"><span class="token keyword">COPY</span> ./ ./</span>
<span class="token comment">#Ejecutamos la instalación de las dependencias que hemos indicado en el package.json</span>
<span class="token instruction"><span class="token keyword">RUN</span> npm install</span>
<span class="token comment"># Le indicamos como comando de arranque el script que hemos indicado en el package.json que básicamente inicia nuestra aplicación en Node</span>
<span class="token instruction"><span class="token keyword">CMD</span> [<span class="token string">"npm"</span>,<span class="token string">"start"</span>]</span>
</code></pre></div>
<p>Ahora si hicieramos un build del contenedor, arrancaramos una imagen y nos conectaramos con <strong>exec -it</strong> podríamos ver que nos conectamos directamente al directorio que hemos indicado como <strong>working directory</strong>....peeeeeero realmente todavía no funcionaria nuestra aplicación, veamos lo último para hacerla funcionar.</p>
<h3 id="mapearpuertoslocalesapuertosdecontenedor">Mapear puertos locales a puertos de contenedor</h3>
<p>El que tenga algunos conocimientos de <strong>node</strong> se habrá dado cuenta de que lo que hacemos es arrancar una aplicación en el puerto <strong>8080</strong>, pero claro, <strong>es el puerto 8080 de nuestro contenedor no de nuestro equipo</strong>, tenemos que pensar que un contenedor es prácticamente como un equipo independiente, como si hablaramos de una <strong>máquina virtual</strong>.</p>
<p>Para poder hacer uso de un puerto del contenedor, tenemos que <strong>mapear</strong> un puerto local a uno del contenedor, no tienen porque ser iguales, pero si tiene que estar libre nuestro puerto local (hace algo similar a una redirección).<br>
Este <strong>mapeo</strong> se hace a la hora de <strong>crear el contenedor no al construir la imagen</strong>, es decir, el mapeo de puertos no se hace en nuestra fase de <strong>docker build</strong>, si no en la fase de <strong>docker create/docker run</strong> de la siguiente manera:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="bash"><pre class="language-bash"><code class="language-bash">docker run -p ptoLocal:ptoContenedor IDimagen
</code></pre></div>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-08-a-las-9.47.32.png" alt="Docker II: Creando contenedores"/></p>
<p>Si ahora hacemos un <strong>docker ps</strong>, veremos que tenemos algo en la columna <strong>PORTS</strong></p>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-08-a-las-9.48.20.png" alt="Docker II: Creando contenedores"/></p>
<p>Con esto ya tendríamos nuestra app funcionando perfectamente, solo tenemos que entrar a <strong>localhost:5000</strong> en nuestro navegador y voilá.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Docker I: Comandos básicos]]></title><description><![CDATA[Un contenedor Docker es en realidad un grupo de recursos que se reserva del
hardware de nuestra máquina para una función específica. Este grupo de recursos
funciona prácticamente como una máquina independiente.
En Mac y en Windows al instalar Docker, lo que realmente se instala es un
máquina virtual Linux donde realmente se hará la gestión de nuestros
contenedores.
Comandos básicos
docker run nombreDeContenedor
Este es el comando básico que aprendemos cuando empezamos a trabajar con Docker.
E]]></description><link>https://jlgarcia.fulldev.ninja/docker-basics-i/</link><guid isPermaLink="false">Ghost__Post__5be004332dd6610fd828c9e4</guid><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Sun, 01 Jul 2018 10:32:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/8250fb6cd246dd294ed3fc4d99218f71/docker_facebook_share.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/8250fb6cd246dd294ed3fc4d99218f71/docker_facebook_share.png" alt="Docker I: Comandos básicos"/><p>Un contenedor Docker es en realidad un grupo de recursos que se reserva del hardware de nuestra máquina para una función específica. Este grupo de recursos funciona prácticamente como una máquina independiente.<br>
En Mac y en Windows al instalar Docker, lo que realmente se instala es un máquina virtual Linux donde realmente se hará la gestión de nuestros contenedores.</br></p>
<h3 id="comandosbsicos">Comandos básicos</h3>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker run nombreDeContenedor
</code></pre></div>
<p>Este es el comando básico que aprendemos cuando empezamos a trabajar con Docker. Este comando hace lo siguiente:<br>
<strong>1.</strong> Comprueba si tenemos en nuestro disco duro la imagen o el fichero de imagen que hemos solicitado.<br>
<strong>2.</strong> Si no lo tenemos se va a buscarlo a la <strong>Docker Hub</strong> (marketplace con todos los contenedores públicos) y lo descarga.<br>
<strong>3.</strong> Crea un contenedor a partir de la imagen que tenemos o teniamos ya en nuestro disco duro.<br>
<strong>4.</strong> Inicia el contenedor pertinente ejecutando el comando de inicio que tenga configurado el contenedor.<br>
<strong>5.</strong> Nos muestra un log con la salida de información que tenga configurado ese contenedor (o con los errores que nos haya generado)</br></br></br></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker create nombreDeContenedor
</code></pre></div>
<p>Esto serían solo los pasos 1,2 y 3, es decir, nos crea el contenedor pero no lo arranca.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker start idDeContenedor
</code></pre></div>
<p>Esto nos inicializa un contenedor a partir del ID que nos ha generado al crearlo o el NOMBRE (OJO no es el nombre de la imagen si no el del propio contenedor). Con <strong>docker start</strong> no veríamos nada en la consola, esto simplemente arranca el contenedor en segundo plano (por decirlo de alguna manera)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker start -a idDeContenedor
</code></pre></div>
<p>Igual que el anterior pero si nos muestra el log por la consola.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker <span class="token function">ps</span>
</code></pre></div>
<p>Con <strong>docker ps</strong> vemos la información de los contenedores que tenemos activos actualmente</p>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-05-a-las-10.01.53.png" alt="Docker I: Comandos básicos"/></p>
<p>Aquí podemos ver:</p>
<ul>
<li><strong>Container ID</strong>: El id único que tiene el contenedor que hemos creado</li>
<li><strong>IMAGE</strong>: La imagen de la que parte el contenedor, es decir, el fichero de configuración a partir del cual se ha creado</li>
<li><strong>COMMAND</strong>: El comando de inicio que ejecuta nuestro contenedor al iniciarse.</li>
<li><strong>CREATED</strong>: Hace cuanto hemos creado el contenedor.</li>
<li><strong>STATUS</strong>: El estado actual del contenedor, si esta arrancado, apagado o en error.</li>
<li><strong>PORTS</strong>: En el caso de que tuvieramos algún puerto de nuestro equipo direccionado a alguno del contender aparecería aquí.</li>
<li><strong>NAMES</strong>: Los nombres que tiene el contenedor, a partir del cual podemos llamarlo como si fuera su ID. Este nombre se crea automáticamente o lo podemos indicar nosotros a la hora de crear el contenedor (docker create o docker run)</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker <span class="token function">ps</span> --all
</code></pre></div>
<p>Nos muestra todos los contenedores que tenemos creados, tanto si están encendidos como si no.</p>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-05-a-las-10.07.33.png" alt="Docker I: Comandos básicos"/></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker system prune
</code></pre></div>
<p>Elimina todos los contenedores parados, las redes sin usar, las imagenes descargadas....</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker stop Id/NameContainer
</code></pre></div>
<p>Envia la señal <strong>SIGTERM</strong> al contenedor para que se apague correctamente cerrando los procesos de la manera correcta.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker <span class="token function">kill</span> id/NameContainer
</code></pre></div>
<p>Envía la señal <strong>SIGKILL</strong> al contenedor, que lo que hace es cerrar todo en plan guantelete del infinito.</p>
<h3 id="quehacercuandouncontenedoryaestaarrancadoyquieroejecutaruncomando">Que hacer cuando un contenedor ya esta arrancado y quiero ejecutar un comando?</h3>
<div class="kg-card kg-code-card gatsby-highlight" data-language="shell"><pre class="language-shell"><code class="language-shell">docker <span class="token builtin class-name">exec</span> -it idContainer Comando
</code></pre></div>
<ul>
<li><strong>exec</strong>: Indicamos que ejecute un comando.</li>
<li><strong>it</strong>: básicamente es que queremos que nos devuelva la consola con el comando que hemos ejecutado. Sin <strong>it</strong> ejecutaría el comando pero no veríamos que pasa.</li>
</ul>
<p>Veamos un ejemplo con un contenedor de <strong>Redis</strong></p>
<p><img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-06-a-las-9.14.04.png" alt="Docker I: Comandos básicos"/></p>
<p>Vemos que se esta ejecutando<br>
<img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-06-a-las-9.14.25.png" alt="Docker I: Comandos básicos"/></br></p>
<p>En este estado podemos ejecutar comandos y tomar control de la sesion<br>
<img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-06-a-las-9.15.05.png" alt="Docker I: Comandos básicos"><br>
<img srcset="/assets/images/2018/11/Captura-de-pantalla-2018-11-06-a-las-9.15.31.png" alt="Docker I: Comandos básicos"/></br></img></br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[jQuery Slideshow]]></title><description><![CDATA[Vamos con un ejemplo de creación de un Slideshow muy simple en jQuery. Lo
primero de todo es generarnos la estructura del proyecto, cada uno que la haga
como quiera, yo tengo algo así
En mi caso voy a usar bootstrap, por comodidad, pero no es necesario, lo añado
al index.html al igual que jQuery. También he creado mi propio fichero de estilo
style.css y lo he añadido, quedando todo de esta manera:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;]]></description><link>https://jlgarcia.fulldev.ninja/jquery-slideshow/</link><guid isPermaLink="false">Ghost__Post__5a8c07c98cda356bbe9bbe44</guid><category><![CDATA[jquery]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 22 Feb 2018 13:10:51 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/d41803bc36890b1c71051dc26c29c3ea/jquery-logo-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/d41803bc36890b1c71051dc26c29c3ea/jquery-logo-1.png" alt="jQuery Slideshow"/><p>Vamos con un ejemplo de creación de un <strong>Slideshow</strong> muy simple en jQuery. Lo primero de todo es generarnos la estructura del proyecto, cada uno que la haga como quiera, yo tengo algo así<br>
<img srcset="/assets/images/2018/02/folders.JPG" alt="jQuery Slideshow"/></br></p>
<p>En mi caso voy a usar bootstrap, por comodidad, pero no es necesario, lo añado al index.html al igual que <strong>jQuery</strong>. También he creado mi propio fichero de estilo <strong>style.css</strong> y lo he añadido, quedando todo de esta manera:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Ninja_slider</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
</body>
</html>
</code></pre></div>
<p>Lo siguiente es añadir donde estará el slider en el <strong>body</strong> de la página</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><body>
<div class="container" align="center">
<h1>Ninja-Slider</h1>
<hr>
<div class="ninjaSlider"></div>
</div>
</body>
</code></pre></div>
<p>Nuestro slider como os podéis imaginar estará en el <em>div</em> con la clase <em>ninjaSlider</em>, y esto es todo por el momento en el html, ahora vamos a nuestro <em>css</em> para darle un poco de estilo y que se vea algo en la página. Le daremos un tamaño y un color de fondo para ir viendo algo.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">.ninjaSlider{
background-color: blue;
width: 600px;
height: 300px;
overflow: hidden;
margin-bottom: 10px;
}
</code></pre></div>
<p>Quedando así<br>
<img srcset="/assets/images/2018/02/background.JPG" alt="jQuery Slideshow"/></br></p>
<p>Bien ahora vamos a crear un fichero <em>js</em> donde meteremos toda la lógica de funcionamiento de nuestro slider. Tener en cuenta que la idea es hacerlo estilo plugin, es decir que este encapsulado para poder usarlo en cualquiera de nuestros proyectos.<br>
Bien lo primero como hemos comentado es crearnos el fichero <em>js</em> y meterlo en la carpeta correspondiente, lo siguiente son las imágenes para que slider tenga algo que mostrar, entonces buscamos unas cuantas imágenes, yo me he descargado 4 y las metemos en la carpeta <em>img</em>.</br></p>
<p>Una vez que tenemos las imagenes ya podemos empezar, con el js. Creamos una función anónima que se ejecute nada más cargar el js en el HTML:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">(function(){
//Aqui dentro meteríamos todo el código.
})();
</code></pre></div>
<p>Vamos a empezar por algo sencillo, que es recibir las imagenes desde el html que es desde donde nos las mandarían si pensamos que este es un plugin. Estas imágenes las incluiremos en una lista, es decir, dentro de un <em>ul</em> de html.<br>
Pero antes de hacer esto, pensemos...¿cómo hacemos para pasar los datos que necesitemos a nuestro plugin?, fácil, por parámetros le pasamos un <em>objecto</em> que tenga las modificaciones que queramos hacer.<br>
Primero creemos un método, que será el que realmente configure e inicie nuestro slider</br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">(function(){
$.ninjaShow = function(config){
}
})();
</code></pre></div>
<p>Aqui hemos añadido la función <em>ninjaShow</em> a jQuery, por lo que la podemos llamar desde cualquier sitio desde el que podamos llamar a jQuery. A esta función le pasamos por parámetro un objeto <em>config</em> que tendrá todos los cambios sobre la configuración por defecto que establezcamos.<br>
Continuemos añadiendo lógica para nuestras imagenes, suponiendo que nos indiquen cuales son las imágenes a través del objeto <em>config</em>, podemos tener nuestras imagenes bajo la propiedad <em>images</em> dentro del objeto <em>config</em>. Hagamos una prueba para que veáis de lo que estoy hablando, nos vamos a nuestro <em>index.html</em> y añadimos lo siguiente al final (pero siempre dentro del <em>body</em>)</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!-- añadimos nuestro js al html -->
<script src="js/slider.js"></script>
<script>
//Llamamos a nuestra función pasandole un objeto con la propiedad images
$.ninjaShow({
images:['img/ninja1.jpg','img/ninja2.jpg','img/ninja3.jpg','img/ninja4.jpg'],
});
</script>
</body>
</code></pre></div>
<p>Y luego en nuestro fichero <em>js</em>, ponemos un log para ver que estamos recibiendo.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">(function(){
$.ninjaShow = function( config ){
console.log(config);
}
})();
</code></pre></div>
<p>Si guardamos y miramos la consola al ejecutar nuestro <em>index.html</em>, veremos algo como lo siguiente<br>
<img srcset="/assets/images/2018/02/images.JPG" alt="jQuery Slideshow"/></br></p>
<p>Es decir, un objeto con la propiedad <em>images</em> y dentro de esta un array con la dirección donde estan nuestras imágenes.<br>
Entonces ya tenemos nuestras imágenes, ahora creemos la lista con ellas.</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">(function(){
$.ninjaShow = function( config ){
//Comprobamos que nos pasan alguna imagen
if (config.images.length == 0){
alert("Necesitamos alguna imagen para mostrar");
return;
}
//Abrimos la lista
var imgList = "<ul>";
//Recorremos el array y vamos añadiendo lineas con nuestra imagen como source
config.images.map((img)=>{
imgList += '<li><img src="'+ img +'"</li>';
})
//Cerramos la lista
imgList += "</ul>";
//Adjuntamos la lista al contenedor
$(".ninjaSlider").append(imgList);
}
})();
</code></pre></div>
<p>Si ejecutamos nuestro <em>index.html</em> veremos algo similar a esto:</p>
<p><img srcset="/assets/images/2018/02/example.JPG" alt="jQuery Slideshow"/></p>
<p>Ahora mismo no vemos casi nada, ¿verdad?, vamos a modificar un poco el estilo para que veamos que realmente las cosas estan donde deben estar. Nos vamos a nuestro <em>style.css</em> y lo dejamos así</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">.ninjaSlider{
background-color: blue;
width: 600px;
height: 300px;
/* overflow: hidden; */
margin-bottom: 10px;
}
.ninjaSlider ul{
padding: 0;
list-style-type: none;
margin-left: 0px;
display: flex;
}
</code></pre></div>
<p>Ahora si veríamos algo aunque solo sean las imágenes<br>
<img srcset="/assets/images/2018/02/example2.JPG" alt="jQuery Slideshow"/></br></p>
<p>Pero si miramos el código fuente de la página deberíamos ver algo como esto:<br>
<img srcset="/assets/images/2018/02/example3.JPG" alt="jQuery Slideshow"/></br></p>
<p>Ya tenemos nuestra lista de imágenes, y las vemos porque hemos cambiado la propiedad <em>overflow</em> de css, la configuración correcta sería descomentado la línea y dejandola así</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">overflow: hidden;
</code></pre></div>
<p>Pero la hemos comentado para explicar que es lo que vamos a hacer para ir cambiando de imágenes.<br>
Si os fijáis las imágenes estan configuradas en una linea horizontal, una al lado de otra, lo que haremos será ir moviendo el interior del contenedor en esa linea horizontal, modificando el <em>margin-left</em>, es decir, supongamos que nuestro <em>margin-left</em> en nuestra primera imagen es 0 y tenemos imágenes con un ancho de 600, pues lo que haríamos para movernos entre las imágenes sería ir modificando el <em>margin-left</em> en conjuntos de 600, es decir, la siguiente imagen tendria un margen de <strong>-600</strong>, la siguiente de <strong>-1200</strong>... y el <em>-</em> es necesario porque nuestro slide se movera de izquierda a derecha y como os podréis imaginar para que funcione en este ejemplo es necesario que el ancho de las imágenes sea el mismo o muy parecido (podríamos manejar el ancho de cada <em>li</em> dentro de la lista pero prefiero dejar el código más claro).<br>
Creo que está más o menos explicado el concepto de lo que queremos hacer, veamos como lo hacemos</br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> //Variable de ayuda para gestionar la posicion
var position = 0;
//Numero de imagenes para controlar
var images = config.images.length;
//intervalo en el que se cambia la imagen
var interval = setInterval(function(){
move();
}, 1400);
function move(){
//Cada vez que pase por aqui aumentamos la posicion
position++;
//Si la posicion es igual o mayor que la cantidad de imagenes
//ponemos position a 0
if (position >= images ){
position = 0
}
//Por ultimo movemos el margen según la posición en grupos de 600
$(".ninjaSlider ul").animate({
marginLeft: position * -600
},400);
</code></pre></div>
<p>Por último descomentamos el <em>overflow:hidden</em> en el fichero <em>css</em> y listo, ya lo tenemos</p>
<p><img srcset="/assets/images/2018/02/slideExample.gif" alt="jQuery Slideshow"/></p>
<p>Ya tenemos nuestro slide funcionando, en este punto podríamos añadir más funcionalidad, que tuviera los puntitos típicos que te indican en que slide te encuentras y que puedes pulsar para moverte de uno a otro, o parar el slide por ejemplo. Eso lo haremos más adelante en algún post posterior ahora quería solo mostrar como podríamos hacer lo más básico de un slide, ahora lo ultimo que haremos será añadir un par de cosas al <em>js</em> para que se vaya pareciendo más a un plugin y podamos personalizarlo un poco más.</p>
<p>Si miramos el código detenidamente y pensamos un poco que cosas podrían ser susceptibles de cambiar, podrían ser:</p>
<ul>
<li>El ancho básico de las imágenes para ir moviendo el slide.</li>
<li>La clase o id del slider (podriamos tener mas de uno por ejemplo)</li>
<li>El intervalo de transición de las imágenes.</li>
</ul>
<p>Estos son algunos de los cambios que se me han ocurrido con el código que tenemos actualmente podríamos tener más seguramente. Por el momento vamos a preparar esos.<br>
Para empezar tenemos que plantearnos cuales son obligatorios y cuales podrían tener una configuración por defecto. Las imágenes deben ser obligatorias, por eso hemos puesto el control antes que nos lanzaría una alerta si no se pasa ninguna imagen, y a lo mejor el nombre del id del slide y el resto podemos tener valores por defecto si no nos lo pasan por parámetro.<br>
Para ellos basta con usar el método <em>extend</em> de jQuery sobre el objeto que se pasa por parámetro</br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$.ninjaShow = function( config ){
config = $.extend({
slideName: "",
width: 600,
timeTransition: 1400,
images: []
}, config);
</code></pre></div>
<p>Este método lo que hace es sobreescribir el objeto local, que sería el primero (el que está entre <em>{ }</em>) con el que se pasa por parámetro, pero solo las propiedades con el mismo nombre, es decir, no elimina el objeto por otro, es como si cambiaramos las propiedades que coincidan por las nuevas que se pasan por parámetro.<br>
Y ahora simplemente es cambiar los elementos que tenemos puestos a mano como <em>".ninjaslider"</em> por la propiedad correspondiente y listo, ya tendríamos preparado el código como si fuera un plugin quedando así (dejo comentado el código)</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Función anonima
(function(){
$.ninjaShow = function( config ){
config = $.extend({
slideName: "",
width: 600,
timeTransition: 1400,
images: []
}, config);
//Comprobamos que nos pasan alguna imagen
if (config.images.length == 0){
alert("Necesitamos alguna imagen para mostrar");
return;
}
//Comprobamos que nos han pasado un nombre para slider
if (config.slideName == ""){
alert("Falta el nombre o id donde estará el slider")
return
}
//Abrimos la lista
var imgList = "<ul>";
//Recorremos el array y vamos añadiendo lineas con nuestra imagen como source
config.images.map((img)=>{
imgList += '<li><img src="'+ img +'"</li>';
})
//Cerramos la lista
imgList += "</ul>";
//Adjuntamos la lista al contenedor
$(config.slideName).append(imgList);
//Variable de ayuda para gestionar la posicion
var position = 0;
//Numero de imagenes para controlar
var images = config.images.length;
//intervalo en el que se cambia la imagen
var interval = setInterval(function(){
move();
}, config.timeTransition);
function move(){
position++;
if (position >= images ){
position = 0
}
$(config.slideName + " ul").animate({
marginLeft: position * - config.width
},400);
}
}
})();
</code></pre></div>
<p>Como véis ahora tenemos <em>config.algo</em> por todas partes. Y para usarlo nos vamos a nuestro <em>index.html</em> y añadimos las propiedades necesarias:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><script>
$.ninjaShow({
slideName: ".ninjaSlider",
ancho: 600,
timeTransition: 1400,
images:['img/ninja1.jpg','img/ninja3.jpg','img/ninja4.jpg'],
});
</script>
</code></pre></div>
<p>Y podríamos como he comentado, crear más sliders simplemente creando el elemento, dandole un nombre y crear un nuevo <em>ninjaShow</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$.ninjaShow({
slideName: ".ninjaSlider",
ancho: 600,
timeTransition: 1400,
images:['img/ninja1.jpg','img/ninja3.jpg','img/ninja4.jpg'],
});
$.ninjaShow({
slideName: ".ninjaSlider2",
ancho: 600,
timeTransition: 1200,
images:['img/ninja4.jpg','img/ninja1.jpg','img/ninja3.jpg'],
});
</code></pre></div>
<p><img srcset="/assets/images/2018/02/2Sliders.JPG" alt="jQuery Slideshow"/></p>
<p>Como véis ahora es muy sencillo crear sliders básicos con este código. En algún post posterior mejoraremos este slider para que tenga más funcionalidades, esto es básicamente para que veamos un poco como podemos trabajar con jQuery para hacer todo lo que queramos con el DOM.</p>
<p>Sin mucho más nos vemos en el siguiente, un abrazooorrrr.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[jQuery Basics I]]></title><description><![CDATA[Empecemos con los básicos de jQuery. jQuery nos permite manejar el DOM de una
manera dinámica, hacer peticiones, manipular datos..... y de una manera muy
sencilla, y realmente podemos hacer casi de todo, iremos viendo un poco de todo
en varios post.
Primero vamos con un ejemplo sencillo
Ejemplo de uso básico de jQuery
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-type" content="text/html">
<title>Leccion 01</title>
<script src="lib/jqu]]></description><link>https://jlgarcia.fulldev.ninja/jquery-basics-i/</link><guid isPermaLink="false">Ghost__Post__5a81da9b8cda356bbe9bbe20</guid><category><![CDATA[jquery]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 20 Feb 2018 11:34:20 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/d41803bc36890b1c71051dc26c29c3ea/jquery-logo.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/d41803bc36890b1c71051dc26c29c3ea/jquery-logo.png" alt="jQuery Basics I"/><p>Empecemos con los básicos de jQuery. jQuery nos permite manejar el DOM de una manera dinámica, hacer peticiones, manipular datos..... y de una manera muy sencilla, y realmente podemos hacer casi de todo, iremos viendo un poco de todo en varios post.<br>
Primero vamos con un ejemplo sencillo</br></p>
<h2 id="ejemplodeusobsicodejquery">Ejemplo de uso básico de jQuery</h2>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-type" content="text/html">
<title>Leccion 01</title>
<script src="lib/jquery-3.3.1.min.js"></script>
</head>
<style>
.textoVerde {
color: green;
}
</style>
<body>
<ul>
<li>Hola 1</li>
<li>Hola 2</li>
<li>Hola 3</li>
</ul>
<ul>
<li>Negrita</li>
<li>Negrita 2</li>
<li>Negrita 3</li>
</ul>
<script>
jQuery('ul').addClass('textoVerde');
jQuery('ul').css('font-weight','bold')
</script>
</body>
<script></script>
</html>
</code></pre></div>
<p>Como véis tenemos un html básico con dos listas, y en ellas cambiamos proopiedades, añadimos una clase css en una de las funciones de jQuery y en la otra le añadimos un estilo de css directamente, esto seria lo mismo que tener un html de esta forma</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-type" content="text/html">
<title>Leccion 01</title>
<script src="lib/jquery-3.3.1.min.js"></script>
</head>
<style>
.textoVerde {
color: green;
}
</style>
<body>
<ul class="textoVerde">
<li>Hola 1</li>
<li>Hola 2</li>
<li>Hola 3</li>
</ul>
<ul style="font-weight:bold;">
<li>Negrita</li>
<li>Negrita 2</li>
<li>Negrita 3</li>
</ul>
<script>
//jQuery('ul').addClass('textoVerde');
//jQuery('ul').css('font-weight','bold')
</script>
</body>
</html>
</code></pre></div>
<p>Si os fijáis hemos comentado los métodos de jQuery y hemos puesto directamente en uno la clase y en el otro un estilo de css.</p>
<h2 id="esperandoaquelapginaestcargadaparaejecutaralgo">Esperando a que la página esté cargada para ejecutar algo</h2>
<p>Algunas veces tenemos en distintos lugares ciertas funciones o variables, esto nos puede dar problemas en lenguajes como html ya que el lenguaje es interpretado de arriba hacia abajo es posible que estemos ejecutando un cambio en un elemento que todavía no ha sido leído por el interprete por lo que el cambio no se producirá, para ello jQuery nos proveé de el método <strong>ready</strong> que nos permite esperar hasta que algo haya sido cargado o leído completamente, veamoslo con un ejemplo.</p>
<p>Si nosotros pusieramos los métodos anteriormente mencionados en el <em>header</em>, por ejemplo, no se produciría ningún cambio en la página (si no os fiáis de mi probarlo ;) ), pero si por lo que fuera tenemos que cargar algo en el header lo podríamos hacer de esta forma</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><script>
$(document).ready(function() {
$('ul').addClass('textoVerde');
$('ul').css('font-weight','bold')
});
</script>
</code></pre></div>
<p>Metiendo nuestro código dentro de la función o método anterior, todo se ejecutará tras la carga de la página o <em>documento</em> completo.<br>
jQuery nos da una forma más corta para hacer lo mismo:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><script>
$(function() {
$('ul').addClass('textoVerde');
$('ul').css('font-weight','bold')
});
</script>
</code></pre></div>
<p>Esto es lo mismo que lo anterior, y si pensamos en las <strong>arrow functions</strong> todavía podemos ahorrarnos algo más:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><script>
$(() => {
$('ul').addClass('textoVerde');
$('ul').css('font-weight','bold')
});
</script>
</code></pre></div>
<p>Las tres son la misma función, solo que como es algo muy habitual de usar, le han dado algo de <em>azúcar sintactico</em> para hacer más cómodo su uso.</p>
<h3 id="trabajandoconselectoresyotrascosas">Trabajando con selectores y otras cosas</h3>
<p>Vamos a ver un ejemplo cortito de uso de algunas funciones para añadir, eliminar clases y atributos a elementos del DOM</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><script>
$("img")
.attr("src","img/photo2.jpg")
.removeClass('img-circle')
.addClass('img-thumbnail');
</script>
</code></pre></div>
<p>Esto lo que hace es: primero cambia el atributo <em>src</em> de la imagen, segundo elimina la clase <em>img-circle</em> y tercero añade la clase <em>img-thumbnail</em></p>
<p>Estas son algunas de las cosas más básicas que podemos ir haciendo con jQuery, iré haciendo más post de jQuery con ejemplos de uso. Nos vemos en el siguiente, un abrazooorrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[MongoDB Ninja(IV): Index Ninja]]></title><description><![CDATA[Hablemos más profundamente sobre los índices,
¿Qué son los índices?
Los índices son una forma muy eficiente de buscar los datos por un valor
específico y nos evita tener que recorrer toda la colección en busca de un dato
específico.
Los índices en las bases de datos tradicionales se basan en Binary Tree Sort, y
Mongo también.
Veamos de una forma muy resumida como funcionaría este tipo de algoritmo.
Binary Tree Sort
Para que nos hagamos una idea, es un tipo específico de ordenación que tiene
es]]></description><link>https://jlgarcia.fulldev.ninja/mongodb-ninja-iv-index-ninja/</link><guid isPermaLink="false">Ghost__Post__5a3a19cf84f3c8302096922d</guid><category><![CDATA[mongodb]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Sat, 23 Dec 2017 19:59:52 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner.png" alt="MongoDB Ninja(IV): Index Ninja"/><p>Hablemos más profundamente sobre los índices,</p>
<h2 id="qusonlosndices">¿Qué son los índices?</h2>
<p>Los índices son una forma muy eficiente de buscar los datos por un valor específico y nos evita tener que recorrer toda la colección en busca de un dato específico.<br>
Los índices en las bases de datos tradicionales se basan en <strong>Binary Tree Sort</strong>, y Mongo también.<br>
Veamos de una forma muy resumida como funcionaría este tipo de algoritmo.</br></br></p>
<h2 id="binarytreesort">Binary Tree Sort</h2>
<p>Para que nos hagamos una idea, es un tipo específico de ordenación que tiene esta pinta</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-16-a-las-9.04.36.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Supongamos entonces que buscamos el número 10, en la búsqueda lo que hace es comprobar los números en la posición en la que está y sigue estos pasos:</p>
<ul>
<li>¿El número que busco es menor que 8? No.</li>
<li>¿Está entre 8 - 12? Sí. Paso la búsqueda por la rama central.</li>
</ul>
<p>Básicamente sigue este orden:</p>
<ul>
<li>Si es menor que el número más a la izquierda pasamos la búsqueda por la rama que esté más a la izquierda.</li>
<li>Si está entre números lo mando por la rama que comprenda esos números.</li>
<li>Si el número es mayor que el número que esta más a la derecha envío la búsqueda por la rama que está más a la derecha.</li>
</ul>
<p>Y así con tantos niveles como tenga el árbol. Aunque en conjunto pueda ser algo más complicado que esto, pero esta es la teoría fundamental de este algoritmo de ordenación/búsqueda. Por dar un dato extra la fórmula de lo que tarda en la búsqueda sería:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">O(log(n))
</code></pre></div>
<p>Creo que no tengo la capacidad para explicar bien la fórmula, tenéis un montón de información al respecto por internet. <a href="https://es.khanacademy.org/computing/computer-science/algorithms/asymptotic-notation/a/big-o-notation">Info</a></p>
<p>Y, ¿que hace la indexación con este algoritmo?...a parte de ordenar los datos de esa manera, intenta que un bloque de números entre en un sector del disco, lo que hace que en una sola pasada sea capaz de leer todos los números de un bloque y así en conjunto se consigue que la búsqueda de elementos sea realmente rápida.</p>
<p>Y después de comentar sobre BTS (Binary Tree Search) continuemos hablando de los índices.</p>
<h2 id="tiposdendices">Tipos de índices</h2>
<p>Ahora viene el cambio de concepto, ya hemos visto en post anteriores como se hacian los índices, digamos, <strong>simples</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionName.createIndex({nombreDelCampo: Ascendente/descendente})
db.heros.createIndex({money:1})
</code></pre></div>
<p>Estos son los índices más habituales y son los que usan <strong>BTS</strong> realmente, pero tenemos otros 2 tipos de índices que no usan este mecanismo de ordenación:</p>
<ul>
<li><strong>Full text Index</strong>: Indices de texto libre. Nos permite buscar el texto que hay en los documentos, es una búsqueda tipo Google. Al generar este tipo de índice crea una base de datos grande con todos los documentos de tipo texto (según los criterios que indiquemos) y a la hora de buscar nos muestras los elementos por relevancia (cuanto más aparezca la palabra que buscamos en el documento, más relevante se vuelve)</li>
<li><strong>Geospatial Index</strong>: Indices de búsqueda geoespacial, que nos permiten manejar datos geográficos, latitudes y longitudes pero no solo puntos si no, nos permiten hacer búsquedas por zonas (en plan datos a mi alrededor o a X Km o si tengo por ejemplo una línea de las de Google maps ruta/origen/destino podríamos buscar lo que está cerca de la línea). Esto se vuelve muy útil para aplicaciones móviles por ejemplo.</li>
</ul>
<h2 id="fulltextindex">Full text Index</h2>
<p>Primero veamos como crear este tipo de índice:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.nameCollection.createIndex({"fieldName": "text"})
db.heros.createIndex({ name: "text"})
</code></pre></div>
<p>Si os fijáis un poco, se crean de la misma forma que habitualmente, solo que en lugar de indicarle la dirección del índice(ascendente/descendente con +/-1) lo que hacemos es indicarle que es de tipo <strong>text</strong>.<br>
Esto nos crea una especie de índice invertido, en el que en lugar de indexar al estilo "esta palabra está en todos estos documentos", lo que hace es darle la vuelta, es decir, este documento tiene estas palabras.<br>
Si hacemos la prueba con el campo name de nuestra colección (sé que no tiene sentido es un campo muy pequeño pero para hacer las pruebas nos vale) y mostramos los índices:</br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.getIndexes()
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-17-a-las-8.45.23.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Vemos como cambia bastante la configuración de uno a otro (el de arriba sería el normal que hicimos con el campo money y el de abajo sería el nuevo).<br>
Para hacer la prueba vamos a cambiarle el nombre a Batman por un párrafo de texto como este:</br></p>
<p><em>"Hero can be anyone. Even a man knowing something as simple and reassuring as putting a coat around a young boy shoulders to let him know the world hadn't ended."</em></p>
<p>Para hacerlo, ya sabéis con:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.update({_id:ObjectId("59e1ff63c5662c1d57baf715")},{$set: {name:"Hero can be anyone. Even a man knowing something as simple and reassuring as putting a coat around a young boy shoulders to let him know the world hadn't ended."}})
</code></pre></div>
<p>Perfecto, y ahora para buscar en este formato:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionName.find({$text: {$search: ""}})
</code></pre></div>
<p>Dentro del habitual find para filtrar tenemos:</p>
<ul>
<li><strong>$text</strong>: Con esto le indicamos que haga una búsqueda de tipo texto.</li>
<li><strong>$search</strong>: Con search lo que hacemos es indicarle que busque por algo.</li>
</ul>
<p>Hagamos alguna búsqueda para ver que pasa:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({$text: {$search: "coat"}}).pretty()
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-17-a-las-9.02.28.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Como véis lo encuentra sin problemas. Las búsquedas de este tipo en mongo parecen ser bastante inteligentes, ignoran las típicas palabras comodines como pueden ser en ingles un <em>"a"</em> o <em>"the"</em> y se centra en el resto, también busca por raiz de palabra, es decir, por palabras que contengan la palabra que estamos buscando (OJO tienen que ser palabras en sí y no mezclas de comodines como <em>some..</em>), por ejemplo:</p>
<p>db.heros.find({$text: {$search: "put"}}).pretty()</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-17-a-las-9.07.04.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Un detalle es que el crea el índice en un idioma específico, por eso puede ignorar ciertas palabras (están soportados la mayoría de los idiomas) y en el caso de que no se le indicara el idioma en el índice, este seguiría siendo funcional pero no tan efectivo ya que nos metería palabras innecesarias en las búsquedas pero a grandes rasgos funcionaría perfectamente.</p>
<p>Como extra comentar que las búsquedas son <strong>caseInsensitive</strong>, es decir, ignora si la palabra está en mayúsculas o en minúsculas y también ignora los acentos (ambas opciones son modificables y lo veremos más abajo)</p>
<h3 id="importantodatos">Importanto datos</h3>
<p>Antes de continuar necesitamos una colección con algo más de información, para ello nos vamos a descargar una de ejemplo oficial de Mongo desde:<br>
<a href="https://raw.githubusercontent.com/mongodb/docs-assets/primer-dataset/primer-dataset.json">AQUI</a> (recomiendo botón derecho- guardar como)</br></p>
<p>Ahora vamos a importarla, para ello nos salimos fuera de la shell de mongo y en la misma ruta donde hacíamos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">bin/mongo
</code></pre></div>
<p>Ejecutamos lo siguiente</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">./mongoimport -c collectionTest -d databaseTest ../primer-dataset.json
</code></pre></div>
<p>Si no esta en esa ruta, buscar el ejecutable <strong>mongoimport</strong>, y lo que hacemos es meter los datos dentro de una colección nombre <em>collectionTest</em> que a su vez estará dentro de una base de datos llamada <em>databaseTest</em> (lo último es el fichero JSON que nos hemos descargado)</p>
<p>Veamos como son los documentos que tiene esta colección, usamos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.findOne()
</code></pre></div>
<p>Y veremos algo similar a esto:</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-17-a-las-21.59.54.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Tenemos coordenadas, que nos serán útiles cuando trabajemos con los índices geoespaciales, y tenemos varios campos de texto como "street", "name" o "cuisine". Con esto lo que vamos a ver es como podemos gestionar nuestros índices para que diferencie la importancia de unos campos de texto u otros y así poder hacer nuestras búsquedas más eficaces. Para ello tenemos la propiedad weights , que mejor que explicarlo creo que es verlo en un ejemplo de uso:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.createIndex({name: "text","address.street": "text",cuisine: "text"},{weights:{name: 5, cuisine: 8, "address.street": 10}})
</code></pre></div>
<p>Si os fijáis hemos creado un índice con los tres campos que he comentado antes, y a continuación le he puesto unos pesos específicos a cada uno, cuanto más alto más importante es el campo. <strong>OJO para los subdocumentos es necesario poner comillas a los nombres de los campos en este caso sería el campo address:{ street}.</strong><br>
He puesto esos números pensando qué a lo hora de buscar un restaurante a no ser que busques un restaurante en concreto con el nombre exacto, sueles buscar una calle a ver que tiene, o lo mejor buscas por un tipo de cocina, pero esto es solo un ejemplo podéis usar la lógica que más os guste. En una aplicación en producción esto habrá que pensarlo más detenidamente.</br></p>
<p>Bueno ahora vamos a probar una búsqueda, y para que sea más visual vamos a solicitarle a Mongo que nos añada una puntuación a la búsqueda. Lo más fácil es verlo con un ejemplo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.find({$text: {$search: "irish"}},{score: {$meta: "textScore"}, name:1, cuisine:1, "address.street":1,_id:0}).sort({score:{$meta: "textScore"}})
</code></pre></div>
<p>Vayamos por orden:</p>
<ul>
<li><strong>$text:{$search: "irish"}</strong>: Esto ya lo hemos visto que es la palabra por la que estamos buscando.</li>
<li><strong>score: {$meta: "textScore"}</strong>: Aquí le indicamos que nos genere un campo con la puntuación del texto.</li>
<li><strong>name:1, cuisine:1, "address.street":1,_id:0</strong>: Si os acordáis de esto, le estamos diciendo los campos que queremos ver para que no nos saque todos, name, cuisine y address.street, y ademas que nos quite el _id que nos molesta.</li>
<li><strong>sort({score:{$meta: "textScore"}})</strong>: Por último le decimos que nos ordene los resultados por la puntuación que ha recibido.</li>
</ul>
<p>Al ejecutarlo obtenemos esto:</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-20-a-las-9.26.25.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Vemos que obtenemos varios resultados (si escribimos it nos saldrán más) y que empiezan por 12.55 de puntuación. En este caso la puntuación es debida a que viene en cuisine y que ocupa gran parte del campo name si os fijáis va bajando la puntuación siempre que el campo name tiene más palabras(y no son comodines como The o a). Como detalle haceros a la idea de que estamos filtrando unos 25000 documentos que yo creo que no está nada mal lo que tarda en devolver los resultados</p>
<p>Bueno supongo que váis viendo un poco como funcionan las búsquedas de texto. Habréis visto que en el campo street no tenemos coincidiencias, vamos a buscar algo relacionado con una calle.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.find({$text: {$search: "Jamaica"}},{score: {$meta: "textScore"}, name:1, cuisine:1, "address.street":1,_id:0}).sort({score:{$meta: "textScore"}})
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-20-a-las-9.29.56.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Veis que sigue el mismo concepto pero esta vez con la calle y el nombre. Estas búsquedas las podemos hacer tan complicadas como queramos igual que el resto que ya vimos anteriormente.</p>
<p>Como extra recalcar que podemos:</p>
<ul>
<li>Modificar el lenguaje del índice con <strong>$language: Idioma</strong>, por ejemplo</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$languaje: Spanish
</code></pre></div>
<ul>
<li>Indicarle que sea <strong>$caseSensitive</strong>:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$caseSensitive: True (default false)
</code></pre></div>
<ul>
<li>Soportar acentos con <strong>$diacriticSensitive</strong>:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">$diacriticSensitive: True (default false)
</code></pre></div>
<p>Creo que con esto es suficiente para que se entienda como funcionan los <em><strong>Full text index</strong></em> y podáis hacer los vuestros según requiera vuestra aplicación. Ahora empecemos con los <em><strong>Indices Geoespaciales</strong></em></p>
<h2 id="geospatialindex">Geospatial Index</h2>
<p>En Mongo tenemos dos tipos de índices <em>Geoespaciales</em>:</p>
<ul>
<li>
<p><strong>2d</strong>: Basicamente representa una cuadrícula sobre un plano, pensado para superficies pequeñas, por ejemplo un campo de fútbol. También si no tenemos pensado usar geoJSON o nos da igual la curvatura de la tierra.</p>
</li>
<li>
<p><strong>2dsphere</strong>: El caso contrario, es decir, situamos cosas sobre la tierra. Este es el más común realmente. Esta basado en el estandar <em>WGS 84</em>, un estandar que intenta simular en una espera a la tierra.</p>
</li>
</ul>
<p>Las posiciones en cualquier mapa están representadas por unas <em><strong>coordenadas</strong></em>, estas coordenadas están representadas en:</p>
<ul>
<li>
<p><strong>Latitud</strong>: Distancia desde el Ecuador al norte y al sur. De 0 a 90 al norte, de 0 a -90 al sur.</p>
</li>
<li>
<p><strong>Longitud</strong>: Distancia desde el <em><strong>Meridiano de Greenwich</strong></em> (seían los 0 Grados). Para localizaciones al este sería de 0 a 180 y para localizaciones al oeste de 0 a -180</p>
</li>
</ul>
<p><strong>OJO las coordenadas en MongoDB se guardan Longitud/Latitud y en Google Maps Latitud/Longitud</strong></p>
<p>Bien ya sabemos un poco de que hablamos, ahora veamos como crear un índice de este tipo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionName.createIndex({campo_localización: "2dsphere"})
</code></pre></div>
<p>(Como véis siempre tiene el mismo estilo la creación de índices) Por si acaso no lo imagináis ya, el campo de localización tiene ser unas <strong>coordenadas</strong> o datos al estilo <strong><a href="http://geojson.org/">GeoJSON</a></strong></p>
<p>Vamos a crear un índice con los datos de las coordenadas que tenemos en la colección que usamos antes, para ello basta con crear el índice:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.createIndex({"address.coord": "2dsphere"})
</code></pre></div>
<p>Ya tenemos nuestro índice creado, ahora vamos a ver como es uno de nuestros elementos con coordenadas</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.findOne()
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-22-a-las-21.22.08.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Y por si acaso nos vamos a ir a Google Maps a comprobar los datos, <strong>OJO recordad que están al revés</strong></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-22-a-las-21.23.32.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Coincide con nuestra calle ¿no?. Bueno pues ahora vamos a probar a buscar por coordenadas directamente, es decir, que me muestre quien contiene la coordenada que pasamos. <strong>OJO la búsqueda que vamos a realizar ahora lo que hace es buscar documentos que contengan esa coordenada, si tuvieramos una base de datos con las coordenadas de los paises enteros podríamos sacar el pais al que pertenece</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.find(
{"address.coord":
{$geoIntersects:
{$geometry:
{type: "Point", coordinates: [-73.9549067, 40.6971322]}}}},{"name":1}).pretty()
</code></pre></div>
<p>Veamos que estamos pidiendo aqui:</p>
<ul>
<li><strong>address.coord</strong>: Esta es fácil le indicamos donde queremos que busque.</li>
<li><strong>geoIntersects</strong>: Es uno de los operadores para buscar con los índices Geoespaciales (tener en cuenta que todo esto esta más pensado para documentos tipo <em>GeoJSON</em>). En este caso lo que hace es buscar geometrias que se crucen con la coordenada que le indiquemos. Veremos alguno más, tenemos 4 distintos. <a href="https://docs.mongodb.com/manual/geospatial-queries/#geospatial-query-operators">Geospatial query operators</a></li>
<li><strong>geometry</strong>: Propiedad para indicarle lo que queremos buscar.</li>
<li><strong>type</strong>: Dentro de type le indicamos el tipo de coordenadas que le vamos a buscar, siempre pensando en formato GeoJSON. En este caso hemos puesto un tipo "Punto". Existen varios distintos, lo mejor es que los veáis en la documentación: <a href="https://docs.mongodb.com/manual/reference/geojson/">GeoJSON Objects</a></li>
<li><strong>coordinates y name</strong>: Básicamente son las coordenadas por las que queremos buscar y lo que queremos que nos devuelva.</li>
</ul>
<p>En este caso la búsqueda parece que es sobre una ubicación específica porque no tenemos coordenadas al estilo <em>"Polígono"</em>, pero es más que nada para que veamos que funciona bien. Al ejecutarlo vemos que nos devuelve el restaurante que habíamos seleccionado</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-24-a-las-9.33.48.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Probemos ahora algo con algo más de "chicha", vamos a buscar restaurantes que estén a unos 500 metros del que hemos seleccionado antes. Para ello en lugar de usar el operador <em>geoIntersect</em> vamos a usar el operador <em>near</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.find({
"address.coord":{
$near:{
$geometry:{
type: "Point",
coordinates: [-73.9549067, 40.6971322]},
$maxDistance: 500
}
}
},{"name":1})
</code></pre></div>
<p>Como propiedad extra que no habíamos visto antes tenemos <strong>$maxDistance</strong>, en la cual indicamos una distancia máxima en metros.</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-24-a-las-9.34.27.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>He cogido las coordenadas de los dos primeros restaurantes y si las ponemos en <strong>Google Maps</strong> (recordemos que tenemos que invertir las coordenadas ya que google las guarda al revés), y esto es lo que aparece</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-25-a-las-9.21.20.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Como véis está a menos de 500 metros, por lo que podemos confirmar que realmente funciona.</p>
<p>Ahora pensemos en otro escenario, las aplicaciones móviles, en la mayoria de los casos cuando buscamos lo que tenemos alrededor en el mapa lo que queremos ver es que se vé en la pantalla, es decir, que hay en la cuadrícula del mapa que estoy mostrando. Esto también lo podemos hacer con MongoDB, solo tenemos que indicarle cuales son las coordenadas que se están mostrando actualmente.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.find({"address.coord":{
$geoWithin: {
$geometry:{
type: "Polygon",
coordinates:[
[[-73,40],
[-75,40],
[-75,42],
[-73,42],
[-73,40]]]}}}},
{"name":1,"address.coord":1,"_id":0})
</code></pre></div>
<p>Si os fijáis en la query hemos cambiado la propiedad a <strong>geoWithin</strong>, es decir, lo que esté dentro de esa zona, y le pasamos un polígono, con 5 coordenadas (imagináos que es una línea que vamos dibujando, que empieza en un punto y tiene que acabar en el mismo punto, por eso son 5 ;) )<br>
Aquí tendríamos una cuadrícula que sería más o menos esta zona</br></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-25-a-las-10.02.34.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Si la ejecutamos veremos que nos saca un montón de coincidencias que son las que están dentro de esa zona (que yo diría que son todos jejeje)</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-25-a-las-10.06.42.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Si por ejemplo contamos los elementos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.find({"address.coord":{$geoWithin: {$geometry:{type: "Polygon", coordinates:[[[-73,40],[-75,40],[-75,42],[-73,42],[-73,40]]]}}}},{"name":1,"address.coord":1,"_id":0}).count()
</code></pre></div>
<p>Nos salen:</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-25-a-las-10.09.53.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Vamos a probar a cambiar, todas las coordenadas -73 por -74 y así comprobamos como nos filtra de verdad:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.find({"address.coord":{$geoWithin: {$geometry:{type: "Polygon", coordinates:[[[-74,40],[-75,40],[-75,42],[-74,42],[-74,40]]]}}}},{"name":1,"address.coord":1,"_id":0})
</code></pre></div>
<p>Si ejecutamos vemos como todos los documentos empiezan a partir de la longitud -74</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-25-a-las-10.11.24.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Si contamos ahora los documentos tenemos</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-25-a-las-10.12.48.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Como vemos realmente si nos está filtrando por una zona en específico. Esto es un ejemplo de algunas cosas típicas que podemos necesitar hacer.</p>
<h2 id="subiendodenivel">Subiendo de nivel</h2>
<p>Bien ahora subamos un poco más el nivel, vamos a ver como podemos programar directamente en la consola de MongoDB, en este ejemplo que vamos a ver seguiremos usando los índices <em>geoespaciales</em> porque son los últimos que hemos visto, pero tener en cuenta que se podría hacer como queráis.</p>
<p>Lo que vamos hacer va a ser recorrer todos los restaurantes que tenemos en la colección de test que estamos usando y vamos a ponerles una propiedad nueva indicando cual es el primer restaurante que esté a menos 500 mt (si hay alguno claro).</p>
<p>Una cosa muy interesante y util en mongo es que podemos usar variables.....y bueno podemos usar un estilo de programación similar al de <em>JavaScript</em>. Entonces para este ejemplo vamos a usar el siguiente código (podéis copiar y pegar ;) )</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var restaurants = db.collectionTest.find()
while(restaurants.hasNext()){
var rest = restaurants.next();
var coords = rest.address.coord;
if (coords != ""){
var neighbour = db.collectionTest.find({"address.coord":{$near:
{$geometry:{type: "Point", coordinates: coords},$maxDistance: 500}}}).skip(1).limit(1);
if (neighbour[0] != undefined){
var neigh = neighbour[0];
db.collectionTest.update({"_id": rest._id},
{$set: {
"address.neighbour": neigh.name
}}
);
}
}
}
</code></pre></div>
<p>En general supongo que más o menos se entiende el código (y no está con la intención de ser el mejor ni el más bonito solo es un ejemplo) pero por si acaso voy a explicarlo paso a paso.</p>
<p>Lo primero almacenamos todos nuestros documentos en una variable, se podría haber limitado la cantidad o cualquier cosa que se os ocurra pero así comprobamos lo que tarda en modificarnos mas de 25000 documentos.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var restaurants = db.collectionTest.find()
</code></pre></div>
<p>Y a continuación por ejemplo haremos un bucle while recorriendo los documentos que tenemos almacenados en la variable <em>restaurants</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">while(restaurants.hasNext()){
</code></pre></div>
<p>Almacenamos el documento en cuestión y las coordenadas de que tiene ese documento:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var rest = restaurants.next();
var coords = rest.address.coord;
</code></pre></div>
<p>Tenemos algunos documentos que tienen la propiedad <em>coord</em> vacía por lo que lo comprobamos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">if (coords != ""){
</code></pre></div>
<p>Lo siguiente será buscar cuál es el restaurante más cercano, sin ser el propio restaurante propietario de esas coordenadas, al buscar por coordenadas nos identifica el primero como el propio restaurante, por eso ignoramos el primer resultado. Y como solo queremos encontrar uno de <em>"los vecinos"</em> limitamos la búsqueda a 1</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> var neighbour = db.collectionTest.find({
"address.coord":{
$near:{
$geometry:{
type: "Point",
coordinates: coords}
,$maxDistance: 500}}}).skip(1).limit(1);
</code></pre></div>
<p>Como es posible que no tengamos nungún documento(restaurante) a menos de 500 metros tenemos que comprobar antes de hacer nada para que el proceso continue</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">if (neighbour[0] != undefined){
</code></pre></div>
<p>Y por último actualizamos el restaurante usando el <em>"_id"</em> añadiendole la propiedad <em>"address.neighbour"</em> con el nombre del restaurante vecino</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.update({"_id": rest._id},
{$set: {
"address.neighbour": neigh.name
}}
);
</code></pre></div>
<p>El proceso tardará un rato, y una vez terminado, si buscamos algún documento</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.collectionTest.findOne({},{"name":1,"address":1,"_id":0})
</code></pre></div>
<p>Veremos como nos ha añadido una nueva propiedad con el nombre de algún restaurante cercano</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-28-a-las-17.49.58.png" alt="MongoDB Ninja(IV): Index Ninja"/></p>
<p>Esto es solo un pequeño ejemplo de lo que podemos hacer con MongoDB, podemos complicar las búsquedas tanto como queramos (aunque lo suyo es que una parte lo hiciera nuestra app no la base de datos sola ;) )</p>
<p>Espero que con este post seais capaces de mejorar vuestros índices y hacer que vuestras búsquedas en vuestras bases de datos MongoDB sean mucho más eficientes. De momento vamos a dejar el tema de los índices, lo próximo que veremos será el <strong>Aggregation Framework</strong>, si no sabéis lo que es no os preocupeis lo veremos en detalle. Nos veeemoosssss un abrazooorrrrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[MongoDB Ninja(III): Sin Scheme]]></title><description><![CDATA[Antes de nada voy a comentar sobre una duda que surgió hace poco en mi entorno
(y aprovechando que este post es más corto lo meto aquí), ¿qué es el journal?.
Para el que no sepa de que hablo si miramos en el filesystem donde se está
almacenando nuestra base de datos tenemos una carpeta journal
Esta carpeta es una colección especial de Mongo en la que se almacenan los datos
temporalmente antes de pasar a nuestro disco duro de forma definitiva. Es un
mecanismo de salvaguarda en caso de que nues]]></description><link>https://jlgarcia.fulldev.ninja/mongodb-ninja-iii/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f43</guid><category><![CDATA[mongodb]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Sun, 29 Oct 2017 20:46:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner-2.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner-2.png" alt="MongoDB Ninja(III): Sin Scheme"/><p>Antes de nada voy a comentar sobre una duda que surgió hace poco en mi entorno (y aprovechando que este post es más corto lo meto aquí), <strong>¿qué es el journal?</strong>. Para el que no sepa de que hablo si miramos en el filesystem donde se está almacenando nuestra base de datos tenemos una carpeta <strong>journal</strong></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-13.21.05.png" alt="MongoDB Ninja(III): Sin Scheme"/></p>
<p>Esta carpeta es una colección especial de Mongo en la que se almacenan los datos temporalmente antes de pasar a nuestro disco duro de forma definitiva. Es un mecanismo de salvaguarda en caso de que nuestro proceso se caiga en medio de algo. Es decir, mongo tiene un proceso que por defecto cada <strong>60 segundos</strong> o cada <strong>2GB</strong> de journal pasa los datos al disco si no han sido pasados antes.<br>
Esto se puede ver cuando arrancamos <em>mongo</em></br></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-13.27.10.png" alt="MongoDB Ninja(III): Sin Scheme"/></p>
<p>Si os fijáis en esa línea, entre otras cosas nos aparece esta línea</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">log=(enabled=true,archive=true,path=journal,compressor=snappy)
</code></pre></div>
<p>Donde indica donde mete los datos de log (que sería el journal), y también tenemos esta otra</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">checkpoint=(wait=60,log_size=2GB)
</code></pre></div>
<p>Que nos índica cada cuanto hace un guardado en disco (cada 60 segundos si no ha escrito o cuando el log llegue a 2GB), pues <strong>el journal sería una colección muy ligera que esta guardando los datos cada 100 ms</strong>, por lo que en el caso de que nuestro servidor se caiga entre <em>checkpoints</em> y no tuvieramos los últimos cambios en el disco, si los tendríamos en el <em>journal</em>.</p>
<h3 id="documentosenmongodb">Documentos en MongoDB</h3>
<p>Hemos comentado que Mongo es una base de datos orientada a documentos (ya lo comentamos por encima jejeje), estos documentos realmente son <strong>objetos JSON</strong>. Estos se almacenan codificados en un formato específico conocido como <strong>BSON</strong> (Binary JSON), los almacena de forma eficiente y nos evita el tener que parsear los documentos, simplemente trabajamos con ellos en su propio formato. Por eso es tan eficiente en las búsquedas.</p>
<h3 id="scheme">Scheme</h3>
<p>Empecemos a comentar cosas sobre el <em>scheme</em>, en Mongo no tenemos un <em>esquema</em> definido pero aún así es algo que tenemos que pensar antes de empezar a trabajar Mongo. Todo se basa siempre en lo mismo: <strong>tiempos de lectura</strong>, es decir tenemos que intentar que para obtener los datos, imaginemos que de este mismo blog, de una de las páginas lo podamos hacer en una única query, ya que en Mongo esto es lo que haría realmente eficiente nuestro <em>esquema</em>. Ya hemos visto lo que tarda realmente en hacer búsquedas de muchos elementos en una sola query (como el ejemplo de los 1000000 elementos del post anterior), si en lugar de hacer una búsqueda única tenemos que mezclar varias querys el tiempo que tardaríamos en mostrar una página sería bastante más alto.</p>
<p>Y pensando en esto es como tenemos que definir nuestros <em>scheme</em> ficticio, ¿que información voy a necesitar en cada momento?. Para explicar esto lo voy a poner con ejemplos similares a los que yo lo aprendí, pensemos otra vez en un blog. Un post de un blog normalmente tiene estos elementos:</p>
<ul>
<li>Titulo</li>
<li>Autor</li>
<li>Fecha de publicación</li>
<li>Texto del post</li>
<li>A lo mejor tiene tags</li>
<li>Comentarios</li>
</ul>
<p>Más o menos esos son los elementos que podríamos decir "básicos" en la mayoría de los post del mundo. Entonces siguiendo la teoría de lo que hemos dicho de <strong>cada documento tiene que tener toda su información para poder traerla en una query</strong> un ejemplo de post sería este:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">{
"post_id": 12334,
"post_title": "Titulo de Post",
"author": "Juan Luis Garcia",
"publish_date": "11-11-1111",
"post_text": "Un montón de palabras juntas contando algo",
"tags":["tag1","tag2","tag3"],
"comments":[{
"comment_author": "Superman",
"comment_date": "12-12-1212",
"comment_text": "Esto es un supercomentario"
},{
"comment_author": "Batman",
"comment_date": "13-13-1313",
"comment_text": "¡¡Soy Batman!!"
},
{...},{...},{...}]
}
</code></pre></div>
<p>Más o menos podría tener sentido, ¿no? pero claro....el tema de los comentarios.......al final según el post podríamos tener un documento gigante y para recorrerlo en busca de algo.....o supongamos que tenemos un montón de comentarios en todos los posts......uffff.....demasiado para que la gestión sea realmente eficiente, planteemonos lo siguiente <em>¿qué es lo que mostramos realmente en el post? ¿mostramos todos los comentarios que tenemos? ¿O realmente tenemos un límite de los que mostramos y luego si el usuario quiere ya pide más?....</em> realmente el escenario normalmente es este último ¿verdad?...bien, pero ¿qué hacemos con el resto de nuestros comentarios?...fácil lo que hacemos es <em>linkarlos</em>, es decir, establecer algún tipo de relación con alguna propiedad.<br>
Vamos paso a paso, primero hemos dicho que tenemos un límite de los post que mostramos inicialmente...supongamos que mostramos 5, entonces no cambia lo que teniamos antes, simplemente que controlamos que tenga 5. Eso lo hacemos con código realmente, es decir depende del cliente...pero y <em>si ya tiene 5, ¿qué hacemos?</em>...alguno pensará que tenemos que hacer una query para eliminar y otra para añadir.....pero realmente no es necesario, tal como es el lenguaje podemos hacer las 2 operaciones en la misma query aprovechandonos de la misma búsqueda</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.blog.update({post_title: "Algo"},{$pop:{comments:1},$push:{comment:.....}})
</code></pre></div>
<p>Con <a href="https://docs.mongodb.com/manual/reference/operator/update/pop/">$pop</a> eliminamos o el último o el primero según queramos y como ya hemos visto con <a href="https://docs.mongodb.com/manual/reference/operator/update/push/">$push</a> añadimos nuevos elementos. Como vemos esta operación realmente puede ser ínfima o tener un precio mínimo, perfecto...y teniendo un límite de 5 comentarios podemos gestionar los documentos de post de una forma bastante eficiente.</p>
<p>Ahora lo siguiente, ¿que hacemos con el resto de los post?, bien lo ideal es tenerlos en otra colección donde hagamos referencia al post en cuestión, por ejemplo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">{
"comment_id": 41325,
"post_id": 12334,
"comment_author": "Superman",
"comment_author_email": "superman@correo.com",
"comment_date": "12-12-1212",
"comment_text": "Esto es un supercomentario"
},
{
"comment_id": 41326,
"post_id": 12334,
"comment_author": "Batman",
"comment_author_email": "batman@correo.com",
"comment_date": "13-13-1313",
"comment_text": "¡¡¡Soy Batman!!!"
}
</code></pre></div>
<p>Cuando el usuario pida más comentarios solo tenemos que buscar por el <strong>post_id</strong> y listo, ya tendríamos todos los comentarios que necesitamos y si os fijáis al separarlo de esta manera tenemos la posibilidad de añadirle más información a los comentarios por si la necesitamos.</p>
<p>Esto es solo un ejemplo de como podemos establecer relaciones en nuestras bases de datos simplemente teniendo una propiedad que relacione ambas, esto se puede complicar tanto como sea necesario, lo único siempre pensar en como se va a trabajar realmente en nuestra aplicación, cuales van a ser las querys que se van a realizar o cuales son las que necesitamos para que sea lo más eficiente posible.</p>
<p>A parte de esto tenemos que ver la posibilidad de gestionar un poco <strong>el no scheme</strong>, es decir, ¿como evitamos que se cambie el esquema si Mongo acepta cualquier cosa que le pasemos mientras tenga un formato JSON correcto?....bueno aquí tenemos dos entornos que podemos gestionar el de la aplicación cliente y el propio de MongoDB.</p>
<p>En cuanto a la aplicación cliente poco que decir, más que realmente la responsabilidad del modelo de los documentos tenía que estar en el cliente ya sea controlándolo a mano o con modeladores de objetos específicos de cada lenguaje, como puede ser <a href="http://mongoosejs.com/"><strong>Mongoose</strong></a> en NodeJS (lo usaremos más adelante).</p>
<p>MongoDB con el tiempo, debido a peticiones de la comunidad añadió a finales de 2015 (si no me equivoco) su propio <em>validador</em> de documentos. Básicamente nos permite controlar qué se inserta o se actualiza en nuestra base de datos, hagamos un ejemplo sencillo solo para que veais un poco funcionaría lo ideal es que miréis la <a href="https://docs.mongodb.com/manual/core/document-validation/">documentación oficial</a> para ver todo lo que podemos hacer con esto. Comentar también que esto debería ser como una segunda comprobación, que exista esta opción no hace que no sea necesaria la opción de controlar los objetos en las aplicaciones cliente.<br>
Vamos a comprobar por ejemplo que en nuestro campo money solo podamos insertar números, ahora mismo tal como lo teniamos podemos insertar propiedades de tipo string sin problemas</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.insert({name: "Deadpool", money: "one hundred"})
</code></pre></div>
<p>Si ahora buscamos a <em>Deadpool</em> y a <em>Black Panther</em> vemos como cada uno tiene un campo <em>money</em> distinto:</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-21.21.31.png" alt="MongoDB Ninja(III): Sin Scheme"/></p>
<p>Para evitar creamos un <em>validator</em> de los datos de una colección ya existente de esta forma:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.runCommand({collMod: "heros",validator: {money: { $type: "number"}}})
</code></pre></div>
<p>En <strong>collMod</strong> le estamos indicando la colección que queremos modificar y como validador le indicamos que el campo <strong>money</strong> tiene que ser de tipo <em>number</em>.<br>
Ahora si intentamos insertar un documento nuevo con el campo money como string</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.insert({name: "Wolverine", money: "two hundreds"})
</code></pre></div>
<p>Obtenemos este resultado<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-21.30.10.png" alt="MongoDB Ninja(III): Sin Scheme"/></br></p>
<p>Tenemos, si o si, que pasarle los datos en el formato que los solicita</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.insert({name: "Wolverine", money: 200})
</code></pre></div>
<p>Para que realmente los inserte en la base de datos<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-21.31.58.png" alt="MongoDB Ninja(III): Sin Scheme"/></br></p>
<p>Estas reglas de validación las podemos hacer tan complejas como queramos, podemos usar expresiones regulares, dar opciones de datos específicas.......lo que he comentado mirar la <a href="https://docs.mongodb.com/manual/core/document-validation/">documentación oficial</a> sobre el tema y vereis que podéis hacer.</p>
<p>Comentar que podemos crear las reglas de validación junto con la creación de la colección</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.createCollection("heros2",{validator: {money: { $type: "number"}}})
</code></pre></div>
<p>Y ya de paso si cremos así la colección nos aparece directamente sin insertar ningún dato, y tenemos también nuestra regla de validación desde el principio.</p>
<p>Bueno hasta aquí el post sobre vivir con <strong>no scheme</strong>, como véis no tenemos un modelado de esquemas al estilo relacional pero creo que entre el poder <strong>linkar colecciones</strong> usando algun campo como referencia y con los <strong>validators</strong> podemos trabajar casi en cualquier entorno que queramos con esta base de datos.</p>
<p>En el próximo post veremos como hacer algunos índices mas complejos como las de <strong>geolocalicación</strong>.</p>
<p>Nos vemos en el siguienteeee un abrazooorrrrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[MongoDB Ninja(II): Queries & Performance]]></title><description><![CDATA[Ahora hablaremos sobre las queries o busquedas que podemos hacer en Mongo, este
post puede que sea algo más corto que el anterior, pero prefería poner esta
parte un poco por separado.
Antes de empezar quiero comentar algunos conceptos similares entre las bases de
datos relacionales y MongoDB pero que quizás tienen distinto nombre:
* Database: O base de datos en relacional es lo mismo en MongoDB.
* Table: O tabla en relacional en Mongo es Colección.
* Row: O fila en relacional en Mongo es Do]]></description><link>https://jlgarcia.fulldev.ninja/mongodb-ninja-ii-queries/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f42</guid><category><![CDATA[mongodb]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 24 Oct 2017 08:21:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner-1.png" alt="MongoDB Ninja(II): Queries & Performance"/><p>Ahora hablaremos sobre las <em>queries</em> o busquedas que podemos hacer en Mongo, este post puede que sea algo más corto que el anterior, pero prefería poner esta parte un poco por separado.</p>
<p>Antes de empezar quiero comentar algunos conceptos similares entre las bases de datos relacionales y MongoDB pero que quizás tienen distinto nombre:</p>
<ul>
<li><strong>Database</strong>: O base de datos en relacional es lo mismo en MongoDB.</li>
<li><strong>Table</strong>: O tabla en relacional en Mongo es <strong>Colección</strong>.</li>
<li><strong>Row</strong>: O fila en relacional en Mongo es <strong>Document/Documento</strong>.</li>
<li><strong>index</strong>: O indice en relacional es lo mismo en MongoDB.</li>
<li><strong>Join</strong>: Como se conoce en relacional en Mongo es <strong>Lookup</strong></li>
<li><strong>Foreign Key</strong>: En Mongo se conoce como <strong>Reference/Referencia</strong>.</li>
<li><strong>Transacciones</strong>: En Mongo existen como transacciones de un unico documento. En relacional son necesarias las transacciones porque tenemos datos que modificar en multiples tablas, sin embargo, en Mongo toda la información que hace referencia a un objeto esta siempre en un unico documento, pensar que más o menos los datos se guardan al estilo JSON, es decir esta todo dentro de un mismo objeto.</li>
</ul>
<p>Primero de todo vamos a crearnos de nuevo nuestra base de datos ya que la eliminamos en el post anterior</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">use ninjas
</code></pre></div>
<p>Y vamos a crearnos 3 elementos o documentos en ella</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.insert({name: "Batman", money: 1000000})
db.heros.insert({name: "Iron Man", money: 5000000})
db.heros.insert({name: "Black Panther", money: 10000000})
</code></pre></div>
<p>Con esto ya tendríamos los 3 creados</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-13.32.26.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Ya vimos como hacer algún filtro básico al estilo, buscame por el nombre X</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({name: "Iron Man"})
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-13.34.23.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>También podemos usar <em>expresiones regulares directamente</em>, imaginemos que queremos que nos muestre todos los elementos que tienen <em>Man o man</em> en su campo <em>name</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({name: /[Mm]an/})
</code></pre></div>
<p>Esto nos devuelve tanto a <em>Batman</em> como <em>Iron Man</em></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-13.10.25.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Podemos <em>limitar</em> o <em>ignorar</em> la cantidad de datos que queremos. Con <strong>limit/skip</strong> y la cantidad de elementos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find().limit(1)
db.heros.find().skip(1)
</code></pre></div>
<p>Pero, ¿y si queremos buscar por dos nombres distintos?...pués para ello usamos <strong>$in</strong> y le pasamos un array con las opciones</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({name: {$in:["Batman","Black Panther"]}})
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-13.39.07.png" alt="MongoDB Ninja(II): Queries & Performance"><br>
(tenemos tambien la opción <strong>$nin</strong> para indicarle que no sea distinto a lo que le indicamos)</br></img></p>
<p>Acabamos de ver un ejemplo buscando dentro de la misma propiedad, pero ¿y para buscar en propiedades distintas?...tenemos un <strong>$or</strong> muy bonito para ello, al cual le pasamos un array con las propiedades que queremos buscar</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({$or:[{name: "Black Panther"},{money: 5000000}]})
</code></pre></div>
<p>Sin problemas nos encuentra lo que buscamos</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-13.43.42.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Hasta el momento hemos realizado búsquedas <em>exactas</em>, es decir, buscábamos por elementos coincidentes 100%, pero no siempre sabemos el número exacto de algo....veamos como podemos realizar búsquedas que cumplan algún tipo de condición, por ejemplo hagamos que nos encuentre todos los elementos que su propiedad <em>money</em> sea superior a <em>5000000</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({money: {$gt:5000000}})
</code></pre></div>
<p>Nos devuelve solo a <em>Black Panther</em></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-13.49.12.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Como os podéis imaginar el <em>$gt</em> es de <em>greather than</em> y al igual que <em>greather than</em>, tenemos <em>less than</em> (lt), <em>greather than or equal</em> (gte) o <em>less than equal</em> (lte). Probemos el gte</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({money: {$gte:5000000}})
</code></pre></div>
<p>Ahora nos devuelve también a <em>Iron Man</em></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-13.51.31.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Todas estas formas de buscar se pueden mezcla entre sí, por ejemplo hagamos una búsqueda que sea menor de 5000000 o mayor de 5000000</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({$or:[{money:{$lt: 5000000}},{money:{$gt:5000000}}]})
</code></pre></div>
<p>Y nos devuelve todo menos lo que era 5000000</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-13.56.16.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Aunque esta búsqueda la podriamos haber realizado de alguna forma más sencilla, es solo para que se vea que podemos mezclar todo como queramos,pero , por ejemplo, podríamos haberlo indicado con un <strong>$nin</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({money: {$nin: [5000000]}})
</code></pre></div>
<p>Veamos algunas cosas más...como tal un documento de mongo no tiene porque tener solo un nivel de profundidad, puede tener un montón de <em>subdocumentos</em> dentro.<br>
Vamos a crearle un subdocumento a Batman indicando si tiene muchos o pocos amigos (al principio solo Alfred jejejeje). Repasamos así como usar <em>update</em></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.update({name: "Batman"},{$set:{friends:{civils: "Alfred",heros: "Robin"}}})
</code></pre></div>
<p>Si ahora buscamos a Batman veamos que tiene (le ponemos pretty para verlo mejor)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({name: "Batman"}).pretty()
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-14.16.12.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>También es posible tener un <em>array</em> de elementos, a los cuales podemos añadir más elementos directamente. Ahora trabajemos con <em>Iron Man</em>, añadamos una array de objetos con algunas de sus armaduras. Primero creemos un array vacio, con <em>update</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.update({name: "Iron Man"},{$set:{armors: []}})
</code></pre></div>
<p>Bien ahora añadamos el primero</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.update({name: "Iron Man"},{$push:{armors: {armor1: "Mark I"}}})
</code></pre></div>
<p>Como véis hemos usado <strong>$push</strong> como modificador para añadir elementos. Si ahora mostramos vemos como tenemos un array con un elemento<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.00.10.png" alt="MongoDB Ninja(II): Queries & Performance"/></br></p>
<p>Probemos añadiendo otro</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.update({name: "Iron Man"},{$push:{armors: {armor2: "HearthBreaker"}}})
</code></pre></div>
<p>Ahora veríamos como tenemos 2 elementos</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.02.11.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<h3 id="performance">Performance</h3>
<p>Hasta ahora hemos visto un poco de todas las operaciones que podemos hacer con mongo, no hemos visto algo que posiblemente algunos se pregunten, ¿es posible insertar más de un elemento?...Por supuesto que sí, pero depende más del lenguaje de programación usado, en general existe un método que es <em>bulkInsert</em> o similar donde pasandole un <em>array,list, arrayList</em>....insertará los registros. Esto lo veremos cuando juntemos <strong>MongoDB con NodeJS</strong>.<br>
Bien ahora vamos a parar un poco y vamos a ver como podemos saber cuanto tardan nuestras querys, que hacen internamente y si podemos mejorar algo. Además veremos como podemos hacer para que nos devuelva solo los datos que queramos y no todo el objeto. Empecemos por esto ya que es lo más sencillo.</br></p>
<p>Para esto simplemente tenemos que indicarlo al hacer el find, probemos por ejemplo a traernos solo el campo money de <em>Black Panther</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({name: "Black Panther"},{money:1})
</code></pre></div>
<p>Como véis solo le pasamos el campo y con <strong>1</strong> indicamos si queremos ese campo, si le pusieramos un <strong>0</strong> sería que no queremos ese, si no el resto.</p>
<p>Con el <strong>1</strong> tendríamos este resultado<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.21.59.png" alt="MongoDB Ninja(II): Queries & Performance"/></br></p>
<p>Con el <strong>0</strong><br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.22.33.png" alt="MongoDB Ninja(II): Queries & Performance"/></br></p>
<p>Entonces como hemos dicho si no quisiéramos ver el campo <em>_id</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({name: "Black Panther"},{money:1,_id:0})
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.23.55.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Ahora supongamos que queremos ordenar la salida. Para ello vamos a quitar el filtro de nombre, dejar que nos muestre <strong>name y money</strong> pero quitando el campo <em>_id</em> y ordenando por <em>money</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({},{_id:0,money:1,name:1}).sort({money:1})
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.29.21.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Esa sería con money de forma ascendente si lo queremos descendente</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({},{_id:0,money:1,name:1}).sort({money:-1})
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.30.16.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Perfecto, ya hemos visto como hacer <em>querys más específicas</em>, ahora veamos como hacen las querys mongo por dentro y como podríamos mejorarlas.</p>
<p>Para obtener información sobre una query tenemos el método <strong>explain()</strong>. Probemoslo por ejemplo con el último comando</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({},{_id:0,money:1,name:1}).sort({money:-1}).explain()
</code></pre></div>
<p>Este comando nos devolvería algo como esto</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.35.51.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Como podéis ver nos proporciona información en cuanto a la configuración de la query, como que hacemos un <em>SORT</em> y nos indica el patrón</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">"stage" : "SORT",
"sortPattern" : {
"money" : -1
},
</code></pre></div>
<p>O por ejemplo en que forma genera el sort y en que dirección</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "COLLSCAN",
"direction" : "forward"
}
}
</code></pre></div>
<p>Aquí tenemos que fijarnos en <strong>COLLSCAN</strong>, esto nos indica que se esta recorriendo toda la colección y luego la ordena (lo mismo nos saldría en una búsqueda sin <em>sort</em>), un poco más abajo veremos como cambia este campo.</p>
<p>Bien tenemos información pero realmente sería ideal poder ver algunas estadísticas de esto como de tiempo por ejemplo...no hay problema solo tenemos que pedirselo a <em>explain</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({},{_id:0,money:1,name:1}).explain("executionStats")
</code></pre></div>
<p>Vemos como además de lo que nos mostraba antes tenemos estadísticas</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.44.30.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Por ejemplo tenemos <em>executionTimeMillis</em> que nos indica el tiempo que ha tardado la query.....en este caso como tenemos pocos datos no tarda nada, pero ahora os voy a mostrar un ejemplo que contiene unos 1000000 elementos y estas serían sus estadísticas</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.46.43.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Fijáos que ha tardado <strong>421 milisegundos</strong> y que el <strong>stage sigue siendo COLLSCAN</strong>. Para mí esta query tardaría mucho, por lo que yo quiero optimizar esta query.....y ¿qué podemos hacer para esto? Antes hemos dicho que al poner <em>COLLSCAN</em> lo que hace es recorrerse toda la colección y luego filtra fijáos en la imagen que pone <strong>totalDocsExamined: 1000000</strong>, para optimizar esto podemos <strong>crear indices</strong>. Esto ya comentamos como era, con <strong>createIndex</strong> con el campo y el orden</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.createIndex({money:1})
</code></pre></div>
<p>Veamos ahora que pone en nuestro <em>explain</em> con nuestra query anterior de <em>sort</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find({},{_id:0,money:1,name:1}).sort({money:-1}).explain()
</code></pre></div>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.53.02.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Si os fijáis ahora ha cambiado nuestro <strong>stage: IXSCAN</strong>, esto nos indica que esta buscando en el índice que hemos creado. No tiene sentido ver el <em>executionStats</em> en nuestro ejemplo porque tenemos pocos documentos, pero ahora os muesto una imagen real del mismo ejemplo de antes de 1000000 de elementos pero con un <em>indice</em></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-15-a-las-12.56.32.png" alt="MongoDB Ninja(II): Queries & Performance"/></p>
<p>Si os fijáis lo primero que vemos es que <strong>executionTimeMillis</strong> es <strong>0</strong> y lo segundo que <strong>totalDocsExamined</strong> son 90, es decir que en el index existen 90 documentos que cumplen con la query que le hemos pasado y nos los ha devuelto directamente.</p>
<p>Aquí podemos ver como realmente los índices tienen una función real y realmente útil. Tenemos que tener cuidado con los índices porque puede parecer que lo mejor es hacer índices de todo, pero realmente no son totalmente gratis, estos ocupan espacio de almacenamiento y el índice se tiene que ir actualizando junto con la base de datos por lo que aumentamos el tiempo de procesamiento a la hora de hacer inserciones en la base de datos, todo esto lo tenemos que tener en cuenta a la hora de crear indices siendo lo ideal planear bien cuales serán nuestras querys más usadas o las más importantes antes de ponernos a crear índices como locos.</p>
<p>Por el momento esto es todo sobre las <em>Queries $ Performance</em> más adelante veremos alguna cosa más pero creo que con esto cubrimos casi todos los escenarios que podemos necesitar en cuanto a <em>queries</em> ser refiere.</p>
<p>En el siguiente post veremos algunas cosas sobre el <em>scheme</em>, como almacena los datos Mongo y varias cosas más...nos vemos en el siguienteeeee un abrazoooorrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[MongoDB Ninja(I): Intro and Shell Basics]]></title><description><![CDATA[Bueno como he ido comentando en los posts de Node empezamos con MongoDB aunque
dentro de poco lo juntaremos con Node para trabajar. Comentar que no todo el
contenido es propiamente mio, está todo basado en conocimientos transmitidos por
KeepCoding y en Webinars oficiales de MongoDB, mezclado con mi experiencia
personal ;)
¿Qué es MongoDB?
MongoDB es una base de datos no relacional sin esquemas.....y esto que
significa:
* No tenemos JOIN, tendremos que hacerlo nosotros
* Cada registro podría]]></description><link>https://jlgarcia.fulldev.ninja/mongodb-ninja-i/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f40</guid><category><![CDATA[mongodb]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 19 Oct 2017 08:26:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/e2d851a4e8d17762251ac236e48b5140/MongoBanner.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/><p>Bueno como he ido comentando en los posts de Node empezamos con <em>MongoDB</em> aunque dentro de poco lo juntaremos con Node para trabajar. Comentar que no todo el contenido es propiamente mio, está todo basado en conocimientos transmitidos por <strong>KeepCoding</strong> y en <strong>Webinars oficiales de MongoDB</strong>, mezclado con mi experiencia personal ;)</p>
<h3 id="quesmongodb">¿Qué es MongoDB?</h3>
<p>MongoDB es una base de datos <em>no relacional</em> sin esquemas.....y esto que significa:</p>
<ul>
<li>No tenemos JOIN, tendremos que hacerlo nosotros</li>
<li>Cada registro podría tener una estructura distinta</li>
<li>Mínimo soporte a transacciones</li>
<li>Como su nombre indica no se basa en las relaciones entre sus elementos.</li>
</ul>
<p>Una base de datos NoSql(el termino por cierto vino de un hastag de twitter no es realmente oficial #nosql) puede darnos bastante más rendimiento que una relacional (según en que entorno por supuesto) por algunas razones como estas:</p>
<ul>
<li>No tiene que gestionar transacciones</li>
<li>No tiene que gestionar relaciones</li>
<li>No es necesario convertir objetos a tablas y tablas a objetos....</li>
</ul>
<p>Definen su propia arquitectura como <strong>Nexus</strong>, porque no es una NoSql típica, cumple con los básicos de una base de datos no relacional:</p>
<ul>
<li><strong>Flexibilidad</strong>: Soporta casi de todos los tipos de elementos que queramos.</li>
<li><strong>Escalabilidad y rendimiento</strong>: Podemos aumentar el número de servidores de base de datos hasta que nos cansemos (todos ellos trabajando en la misma) y el rendimiento aumentaría casi de forma lineal (esa es la teoría).</li>
<li><strong>Siempre disponible y despliegue global</strong>: Viene muy relacionado con el punto anterior, porque tener muchos servidores nos garantiza disponibilidad, y esos mismos servidores pueden estar distribuidos por todo el mundo.</li>
</ul>
<p>Pero además de cumplir como <em>NoSql</em> tiene características que la hacen ser algo más (al estilo relacional):</p>
<ul>
<li><strong>Lenguaje de querys muy expresivo</strong>: Podemos crear querys casi tan complejas como en un lenguaje relacional.</li>
<li><strong>Indices secundarios</strong>: Tras usar un indice principal para una búsqueda, si previamente lo hemos configurado usaría otro secundario (pensando en querys complejas donde se vayan cumpliendo cosas) lo que hace que la busqueda sea muy agil.</li>
<li><strong>Fuerte consistencia</strong></li>
<li><strong>Enterprise Management & Integrations</strong>: Esta pensada para trabajar casi en cualquier entorno, con múltiples sistemas de integración y con gestión empresarial.</li>
</ul>
<p>Podemos comentar también que no tiene <strong>esquema definido</strong>, toda la responsabilidad del orden de los datos la tiene la aplicación que use la base de datos, es decir, si queremos de repente tener un campo nuevo solo tenemos que hacerlo directamente en nuestro código Java, JavaScript,etc.... y MongoDB lo aceptará.</p>
<p>No voy a entrar en temas de escalabilidad y tolerancia a fallos muy a fondo, solo comentar que:</p>
<ul>
<li>Tenemos escalabilidad podríamos decir <em>vertical</em>, lo que se conocería como <em>Replica Set</em>, serían varios servidores juntos en los que tenemos uno primaria y otros secundarios que van compartiendo información, cuando uno falla en unos 2 segundos se levantará uno de los secundarios. Por lo que realmente cualquiera puede ser primario o secundario.</li>
<li>Y también tenemos escalabilidad horizontal, conocida como <em>shards</em>, cada <em>shard es un conjunto de replica set</em> normalmente separados geográficamente o por lo menos no están agrupados como sería con los <em>replica set</em>. Dentro de este entorno podemos definir que se replica y donde, por ejemplo por temas de la LOPD solo queremos que los datos de España se repliquen en servidores que esten en España. Y para controlar que querys van a que servidor tenemos un proceso llamado <strong>MongoS</strong> (Mongo Shard Router), que normalmente existe uno por servidor, que es el que se encargaría de dirigir estas querys a su lugar correcto.</li>
</ul>
<p>Creo que hasta aquí tenemos lo básico sobre Mongo, continuemos con la instalación.</p>
<h3 id="instalacin">Instalación</h3>
<p>Más que instalación yo diría que es descarga y ejecución pero bueno mantengamos el orden un poco :P.<br>
Tenemos varias opciones, definidas también según nuestro sistema operativo: <a href="https://docs.mongodb.com/manual/tutorial/install-mongodb-on-linux/">Linux</a>, <a href="https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/">Windows</a> o <a href="https://docs.mongodb.com/master/tutorial/install-mongodb-on-os-x/">MacOS</a>.<br>
En general es bastante sencillo, se instala/descarga y se ejecuta definiendo el path donde se guardará nuestra base de datos, en mi caso trabajo en el blog con MacOS asi que los ejemplos pueden estar un poco más enfocados a este sistema operativo pero intentaré ser lo más genérico posible.<br>
Una vez instalado y ejecutado (cada uno que situe la base de datos donde quiera tal como lo pone en la documentación de instalación) por defecto estará esperando conexiones en el <strong>puerto 27017</strong>, pero se podría cambiar por cualquier otro sin problema.<br>
En windows se gestiona su arranque y detenimiento con comandos específicos que vienen en la documentación, en el caso de linux y mac, si lo hemos realizado descargando e instalando tendremos un shell que es donde veremos los logs de consola que muestra mongo, para pararlo solo tenemos que cerrar la ventana o parar el proceso como cualquier otro.<br>
Bien, una vez ejecutado, para trabajar de primeras con Mongo nos vamos a la carpeta donde tengamos descargado Mongo y dentro y podemos ejecutar</br></br></br></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">bin/mongo
</code></pre></div>
<p>Esto nos abrirá una conexión en shell con la base de datos<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-21.40.31.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></br></p>
<p>Y esto sería lo que muestra el log de consola de Mongo<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-21.41.40.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></br></p>
<p>Una vez conectados, veamos algunos comandos básicos de uso de MongoDB.</p>
<ul>
<li><strong>show dbs</strong>: Nos muestra las bases de datos que tenemos actualmente.</li>
<li/>
</ul>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-21.45.29.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></p>
<ul>
<li><strong>use nameDB</strong>: Para hacer gestiones en una base de datos específica. Esto también lo usaríamos para crear bases de datos nuevas (OJO hasta que no introduzcamos datos no nos aparecería)</li>
</ul>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-21.47.06.png" alt="MongoDB Ninja(I): Intro and Shell Basics"><br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-21.51.56.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></br></img></p>
<ul>
<li><strong>show collections</strong>: Muestra las colecciones existentes en esa base de datos (para haceros una idea serían algo así como las tablas en bases de datos relacionales)</li>
</ul>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-21.48.56.png" alt="MongoDB Ninja(I): Intro and Shell Basics"><br>
Si la base de datos es nueva de primeras no habría nada, las colecciones se crearián cuando insertemos algo (al igual que cualquier base de datos nueva), entonces vamos a insertar algo. Los datos en <em>Mongo</em> tienen un estilo similar <em>json</em>, al estilo clave => valor</br></img></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.insert({name: "Batman", powers: "Money"})
</code></pre></div>
<p>Al insertar algo correctamente la consola nos lo indicaría</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-12.18.06.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></p>
<p>Una vez insertado si ahora hacemos un <em>show dbs</em> nos mostraría la nueva base de datos, y lo mismo al hacer <em>show collections</em> tras seleccionar esa base de datos</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-12.20.30.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></p>
<ul>
<li><strong>Ver lo que tiene una colección</strong>: Para ver lo que tiene una colección lo hacemos con <em>db.collectionName.find()</em>, es decir:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.find()
</code></pre></div>
<p>También podemos ponerle <em>.pretty()</em> al final para que nos lo muestre en un formato quizá más cómodo si tenemos varios objetos</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-12.22.35.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></p>
<p>Si os fijáis tenemos una nueva propiedad en nuestro objeto que es <em>_id</em>, esta propiedad es un identificador único de objeto que le asigna <em>Mongo</em> por defecto a cada elemtento insertado. Vamos a crear alguno más para probar a borrar y actualizar alguno</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.insert({name: "Superman", powers: "is Super, no more"})
db.heros.insert({name: "Goku", powers: "Super Saiyan"})
</code></pre></div>
<p>Si ahora hacemos un <em>find</em></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-12.31.53.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></p>
<p>Ya tenemos varios documentos, ahora vamos a eliminar alguno para probar, por ejemplo borremos a Superman. Os podéis imaginar pero veamos</p>
<ul>
<li><strong>Eliminar un elemento</strong>: Lo hacemos de manera similar al <em>insert</em> con <em>db.colectionName.remove(idObject)</em></li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.remove({_id: ObjectId("59e1e758c5662c1d57baf70f")})
</code></pre></div>
<p>Esto nos indica que ha eliminado un elemento y si hacemos un <em>find</em> de nuevo tenemos solo dos elementos</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-12.50.41.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></p>
<ul>
<li><strong>Actualizar un elemento</strong>: Sigue la misma teoria que el resto, pero en este caso, a parte del criterio de búsqueda del objeto tenemos que indicarle también que es lo que actualizamos. En este caso en lugar de usar el <em>id</em> para encontrar un objeto lo haremos con otra propiedad, por ejemplo el nombre</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.update({name: "Batman"}, {$set: {powers: "Ninjitsu"}})
</code></pre></div>
<p><strong>OJO con $set, si no lo ponemos así nos sustituiría todo el elemento por lo que le hubieramos pasado</strong>.</p>
<p>Tras ejecutarlo, como siempre, la consola nos indica lo que ha hecho y si buscamos a <em>Batman</em> veremos como ha cambiado su propiedad <em>powers</em></p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-12.58.56.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></p>
<ul>
<li><strong>Crear indices</strong>: Si vamos a buscar mucho por cierta propiedad en nuestros documentos dentro de mongo lo ideal es crear indices, ya que agilizan las búsquedas bastante, sobre todo cuando tenemos muchos elementos. Para ello es tan fácil como <em>createIndex</em> y dentro el orden del índice.</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.createIndex({name: 1, powers: -1})
</code></pre></div>
<p>En este índice lo que le hemos puesto es que cree un índice primero por <em>name</em> con orden <em>ascendente</em> y eso mismo si el nombre es el mismo que lo ordene por la propiedad <em>powers</em> de forma <em>descendente</em> (creo que el +1 -1 está más o menos claro). Si queremos ver los índices que tenemos creados solo tenemos que hacer <em>getIndexes()</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.heros.getIndexes()
</code></pre></div>
<p>Y nos devolverá algo como esto</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-13.10.43.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></p>
<p>Como véis ya existia un índice ascendente por <em>_id</em> y luego esta el nuestro que acabamos de crear. Podemos ver más opciones con los índices en la <a href="https://docs.mongodb.com/manual/indexes/">documentación oficial</a></p>
<ul>
<li><strong>Eliminar una colección entera</strong>: Fácil <em>db.colectionName.drop()</em></li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">db.ninjas.drop()
</code></pre></div>
<p>Al no tener ninguna tabla más o colección nos eliminará también la base de datos</p>
<p><img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-14-a-las-13.25.34.png" alt="MongoDB Ninja(I): Intro and Shell Basics"/></p>
<p>De momento lo vamos a dejar con la base de datos eliminada en el próximo post la crearemos de nuevo con otros elementos.</p>
<p>Estas serían las opciones más básicas, como tal en la <a href="https://docs.mongodb.com/manual">documentación oficial</a> tenemos muchas más.</p>
<p>Un abrazoooorrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(XIII) Cluster]]></title><description><![CDATA[Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que
veremos con será, después de MongoDB, como usar las 2 cosas para hacer una API
completa.
Aunque sea lo último no tiene porque dejar de ser interesante, ya que usando lo
que veremos a continuación podemos aumentar el rendimiento de nuestra aplicación
notablemente (eso sí, siempre dependiendo del entorno).
¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más
servicios, programas, ordenadores, se]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-xiii-cluster/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f3e</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 16 Oct 2017 08:28:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-1.jpg" alt="Don't stop the party: Node JS(XIII) Cluster"/><p>Y por fin hemos llegado a la última parte exclusiva de Node, ya lo siguiente que veremos con será, después de MongoDB, como usar las 2 cosas para hacer una API completa.<br>
Aunque sea lo último no tiene porque dejar de ser interesante, ya que usando lo que veremos a continuación podemos aumentar el rendimiento de nuestra aplicación notablemente (eso sí, siempre dependiendo del entorno).<br>
¿Y que es un Cluster? Bueno pues para hacerlo simple un cluster son 2 o más servicios, programas, ordenadores, servidores....que funcionan como uno solo. Bajo este concepto tendríamos varías opciones de configuración: balanceo de carga, alta disponibilidad.... Si queréis saber más siempre podéis mirar en la <a href="https://es.wikipedia.org/wiki/Cl%C3%BAster_(inform%C3%A1tica)">Wiki</a><br>
En nuestro caso, NodeJS, nos permite tener varios <em>workers</em> que trabajan por si solos, para hacerlo simple es como si iniciaramos varias veces nuestra aplicación de NodeJS y cada una trabajara por si sola (realmente tenemos un proceso <em>master</em> que gestiona el resto y podemos pasar datos, comunicar eventos o lo que necesitemos entre los workers, entre los workers y el master y viceversa).<br>
Para configurarlo en nuestra aplicación de node tenemos que hacerlo antes de que inicie el <em>server</em> para <em>escuchar</em> las peticiones por lo que vamosa nuestro proyecto de <em>Express</em> y dentro de la carpeta <strong>bin</strong> en el fichero <strong>www</strong> hacemos lo siguiente:<br>
Buscamos la linea donde tenemos el comentario <em>Create server</em></br></br></br></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">/**
* Create HTTP server.
*/
var server = http.createServer(app);
</code></pre></div>
<p>Y justo encima ponemos lo siguiente:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">const cluster = require('cluster')
if (cluster.isMaster){
console.log(`Master is running in process ${process.pid}`)
const numCPUS = require('os').cpus()
numCPUS.map(() => {
cluster.fork()
})
}else {
/**
* Create HTTP server.
*/
var server = http.createServer(app);
</code></pre></div>
<p>Como véis lo que hacemos es <em>requerir</em> el módulo <strong>cluster</strong> y básicamente es que si es el <em>Master</em> comprobamos cuantas CPUs tenemos y generamos un <em>worker</em> por cada una. El <em>numCpus</em> lo que devuelve es un array donde cada elemento es información de cada CPU, yo simplemente he recorrido el array con el map y por cada elemento le he indicado que genere un <em>worker</em>. Esto se podría hacer de más formas con un <em>for</em> normal o como queráis.<br>
Para ver cuantos workers instancia vamos a añadir un log que indique que ha iniciado un worker, justo debajo de los <em>server.on</em> y cerramos el <em>else</em></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
console.log(`Worker ${process.pid} Started`)
} //No nos olvidemos de cerrar el else en este punto
</code></pre></div>
<p>Bien creo que ya estamos listos para ejecutarlo, asi que ya sabéis</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm start
</code></pre></div>
<p>Y si miramos el log<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-18.58.14.png" alt="Don't stop the party: Node JS(XIII) Cluster"><br>
A mi me ha arrancado 4 <em>workers</em>, esto dependerá del número de CPUs de cada equipo.<br>
Hablemos un poco más de como funciona un cluster en <em>Node</em>. En este caso específico se útiliza el método <a href="https://es.wikipedia.org/wiki/Planificaci%C3%B3n_Round-robin"><strong>round-robin</strong></a> para repartir la carga entre los workers (lo mejor es que miréis el link que he puesto si queréis saber como funciona).</br></br></img></br></p>
<p>Tango el <em>master</em> como los <em>workers</em> producen eventos a los que nos podemos <em>suscribir</em>, al mismo estilo que hicimos con el <a href="/dont-stop-the-party-node-js-v/"><em>event emitter</em></a> en su momento, lo más fácil para que veais que eventos tenemos y que podemos hacer con ellos es que miréis la <a href="https://nodejs.org/dist/latest-v8.x/docs/api/cluster.html">documentación oficial</a> que como veréis viene con mucho código de ejemplo para que lo entendáis mejor.<br>
También es posible que el master mande mensajes a los workers, veamoslo con un pequeño ejemplo. Dentro del <strong>if</strong>, es decir en el <em>master</em> añadimos</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> //Nos da una lista con los workers que tenemos
const workersOnline = cluster.workers
workersOnline[2].send("Hi ninjaWorker 2")
workersOnline[4].send("Hi ninjaWorker 4")
</code></pre></div>
<p>Y en el <em>else</em> donde instanciamos los <em>workers</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">process.on('message',(message)=>{
console.log(`Soy un worker y este es el mensaje ${message}`)
})
</code></pre></div>
<p>Nos suscribimos al evento <em>message</em> y devolvemos un mensaje en consola con el mensaje, fácil ¿verdad?, si ahora ejecutamos veremos como nos aparece el mensaje que hemos pasado a cada <em>worker</em>, y además cada vez que ejecutemos nos aparecerá en distinto momento ya que no sabemos cuando se instancia cada <em>worker</em><br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.09.png" alt="Don't stop the party: Node JS(XIII) Cluster"><br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-12-a-las-19.16.34.png" alt="Don't stop the party: Node JS(XIII) Cluster"/></br></img></br></p>
<p>Esto solo es un ejemplo si repasais la documentación veréis que podéis hacer multitud de cosas distintas ;)</p>
<p>Bueno y hasta aquí la parte de <em>Cluster</em>, como habéis visto es relativamente sencillo y ya podéis usarlo tranquilamente en vuestros proyectos con <em>NodeJS</em>.</p>
<p>También (por el momento) aquí finalizamos la parte específica de <strong>Node</strong> ya lo siguiente que veremos será usandolo con MongoDB para trabajar con esta base de datos y crear una <em>API Rest</em> con un entorno más realista, así que empezaré con una nueva línea dedicada a <em>MongoDB</em> dentro de nada, espero que la parte de Node os haya parecido interesante y suficiente para poder realizar vuestros propios proyectos.</p>
<p>Estad atentos a los siguientes ;) nos vemooosssss un abrazoooorrrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(XII) Promesas]]></title><description><![CDATA[Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero
realmente son muy útiles.
Promesas
Las promesas, si no estoy mal, se añadieron oficialmente en JS a partir de
ES6...y por resumir un poco, son como callbacks de finalización pero en bonito,
explicome....cuando necesitamos encadenar métodos que continenen callbacks
podemos terminar con un código de este estilo
Realmente es raro que nuestro código termine así, pero realmente esa es la
tendencia , ¿verdad?.. bueno p]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-xii-promesas/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f38</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 12 Oct 2017 08:10:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" alt="Don't stop the party: Node JS(XII) Promesas"/><p>Bien, en este post vamos a ver algunos extras que no son exclusivos de Node pero realmente son muy útiles.</p>
<h3 id="promesas">Promesas</h3>
<p>Las promesas, si no estoy mal, se añadieron oficialmente en JS a partir de ES6...y por resumir un poco, son como callbacks de finalización pero en bonito, explicome....cuando necesitamos encadenar métodos que continenen callbacks podemos terminar con un código de este estilo<br>
<img srcset="/assets/images/2017/10/callBack_hell.gif" alt="Don't stop the party: Node JS(XII) Promesas"/></br></p>
<p>Realmente es raro que nuestro código termine así, pero realmente esa es la tendencia , ¿verdad?.. bueno pues una de las cosas que nos ayudan a mejorar las <em>promesas</em> es esa. Por definir concretamente:<br>
<em>Una promesa es un objeto que, si todavía no ha terminado, aseguramos que se completará más adelante</em>.</br></p>
<p>Supongo que con esa frase queda más claro todavía qué es una promesa (y también su nombre jeje). Las <em>promesas</em> tienen tres estados en su ciclo de vida:</p>
<ul>
<li><strong>Pendiente(pending)</strong>: Como su nombre indica todavía está sin cumplir y cambiará de estado en algún momento.</li>
<li><strong>Completada correctamente(Fullfilled/resolve)</strong>: Es decir, ha hecho su trabajo correctamente y ha devuelto un valor.</li>
<li><strong>Rechazada(rejected)</strong>: En su proceso de ejecución ha dado algún tipo de error y ha sido completada con error devolviendonos la razón.</li>
</ul>
<p>Veamos ahora como podemos crear una promesa</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var prom = new Promise(function(resolve,reject){
})
</code></pre></div>
<p>Básicamente creamos un nuevo objeto <strong>Promise</strong> el cual tiene una función que recibe dos parámetros, con un nombre bastante intuitivo por cierto:</p>
<ul>
<li><strong>resolve</strong>: Llamaremos a resolve cuando todo haya ido bien y le pasamos el resultado que recibirá la siguiente <em>promesa</em> o función.</li>
<li><strong>reject</strong>: Llamaremos a <em>reject</em> cuando tengamos un error, al cual le pasaremos el error.</li>
</ul>
<p>Y, ¿como usamos esto? Bastante sencillo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">prom.then(function(resultado){
//Lo que queramos hacer con el resultado
}).catch(function(error){
//Lo que queramos hacer si hemos recibido error
});
</code></pre></div>
<p>Esto lo que hace es ejecutar la promesa que hemos creado y a continuación (<strong>then</strong>) se ejecutará la función dentro del <em>then</em> donde <strong>resultado</strong> es el parámetro que hemos recibido desde la promesa con <em>resolve</em>. En el caso de que algo hubiera fallado o el resultado fuera insatisfactorio ejecutariamos <em>reject</em> con el error o la información que quisieramos, la cual capturaría el primer catch que encontrará la cadena de <em>promesas</em>. Por si no os lo habéis imaginado nosotros podemos poner todas las promesas y catch que queramos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">prom.then().then().then().catch().then().catch()
</code></pre></div>
<p>Y en el orden que las hemos escritor se irian ejecutando, y también según ese orden el primer catch que se encontrara sería el que respondería en caso de tener un resultado <em>reject</em>.<br>
Hagamos un ejemplo encadenando promesas y de paso le ponemos algún <em>catch</em>. Vamos a crear un método nuevo junto con el que ya teníamos que lo vamos a modificar, la idea es que cada promesa vaya encadenando un String hasta mostrarlo al final, aunque en este caso lo que haremos será mostrarlo en cada paso para que se vea que esta haciendo.<br>
Primero cambiamos nuestra función <em>sleep</em></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Seria una funcion que devuelve una promesa
function sleep(ms,hero) {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve("La liga de la justicia: " + hero)
}, ms);
});
}
const prom = sleep(2000, "Superman");
</code></pre></div>
<p>Le pasamos el parámetro <em>hero</em> y devolvemos un string. A continuación creamos otro método que vaya encadenando</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function heros(result, hero){
return new Promise((resolve,reject) => {
/*if (hero === "Green Latern"){
reject("No aparece esta vez")
}*/
console.log(result)
setTimeout(()=> {
resolve(result + " " + hero)
},2000)
})
}
</code></pre></div>
<p>De momento dejamos comentada la parte de <em>reject</em> para ver el resultado. Como véis la función recibe un parámetro <em>result</em> (este primer parámetro sería lo que nos devuelve la promesa en caso de <em>resolve</em>) y también un parámetro extra con el nombre de otro <em>hero</em> y luego simplemente lo juntamos todo para que lo devuelva en 2 segundos.<br>
Ya tenemos nuestros métodos ahora vamos a encadenar las promesas</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">prom
.then((result) => {
return heros(result, "Batman")
})
.then((result) => {
return heros(result, "Green Latern")
})
.then((result) => {
return heros(result, "Wonder Woman")
})
.catch((err) => {
console.log(err)
})
.then((result) => {
return heros(result, "Aquaman")
})
.then((result)=> {
console.log(result)
})
</code></pre></div>
<p>De paso le he metido un catch para probar el error más adelante. Fijáos que lo que hacemos es retornar dentro de una función anónima, que es la que recibe <em>result</em>, la promesa resultante de nuestra función <em>heros</em>, si no necesitaramos <em>result</em> no tendríamos porque meterlo dentro de otra función, bastaría solo con usar <em>heros("New Hero")</em>. Bueno y ahora si lo probamos<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-8.58.17.png" alt="Don't stop the party: Node JS(XII) Promesas"><br>
Vemos como cada 2 segundos nos aparece el string con el nuevo héroe.<br>
Por último vamos a probar el catch para que veais como funciona, lo que haremos será descomentar el código que tenía reject y ya podríamos probarlo.<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.01.28.png" alt="Don't stop the party: Node JS(XII) Promesas"><br>
Vemos que cuando le toca el turno a <em>Green Latern</em> pasa por el <em>catch</em> pero no se detiene y continua......eso es porque tenemos que cambiar como funciona el <em>catch</em> ya que solo hemos puesto un <em>console.log</em> para que se vea que pasa por allí, para hacer que se detenga podemos poner</br></img></br></br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">catch((err) => {
throw err
})
</code></pre></div>
<p>Y ahora sí tendríamos un error al <em>estilo promesas</em><br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-09-a-las-9.09.06.png" alt="Don't stop the party: Node JS(XII) Promesas"/></br></p>
<p>Con promesas tenemos también otras opciones, por ejemplo podemos pasar un array de promesas y cuando terminen todas pasa al <em>then</em> o al <em>catch</em> según si ha dado error o no.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">Promise.all(arrayPromises)
.then((result) =>{console.log(result)})
.catch((error){})
</code></pre></div>
<p>Con <em>Promise.all</em>, pasamos una array de promesas y esperamos a que terminen todas, tenemos también la opción de que pase al <em>then</em> cuando responda la primera</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">Promise.race([arrayPromises])
.then((result) => { console.log("La más rápida ha sido" + result)})
</code></pre></div>
<p>Este concepto es útil por ejemplo si tenemos varios servidores de base de datos, hacemos las llamadas pertinentes en cada una de las promesas y en cuanto uno termine ya tenemos un resultado, lo que nos permite responder lo más rápido posible ignorando si un servidor tiene más carga que otro.</p>
<p>Ahora pasemos al siguiente nivel en las promesas, no en dificultad, pero si en un extra o forma de usarlas que, si no me equivoco, salió en ES7 y <strong>para esto es necesario tener Node actualizado a la última versión o por lo menos en la 7.6 (creo)</strong>, con <strong>node -v</strong> podéis ver en que versión estáis y actualizar si lo necesitáis.</p>
<p>Concretamente vamos a hablar de <strong>async/await</strong>. Estos nuevos métodos nos ayudan un poco con la gestión de las promesas, y de los callbacks por supuesto. Lo que hacemos con <strong>await</strong> es esperar a que una función termine y parece ser que como <em>best practice</em>(o que tiene que ser si o sí más bien) tenemos que hacer ese código asíncrono asi que nos han puesto <strong>async</strong> para facilitarnos esa tarea. Y como funciona esto? Pues vamos a ver un ejemplo sencillo con lo que más o menos teníamos antes.<br>
Partimos de esto</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict'
//Seria una funcion que devuelve una promesa
function sleep(ms,hero) {
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve("La liga de la justicia: " + hero)
}, ms);
});
}
</code></pre></div>
<p>Se supone que tenemos que usar <em>await</em> para que el código se espere a que termine la promesa y meterlo todo dentro de <em>async</em>...pues vamos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">async function asyncPromise(){
console.log("Empezamos a contar")
return await sleep(2000,"Superman")
}
</code></pre></div>
<p>Como véis simplemente hemos puesto <em>await</em> al principio de la ejecución de nuestra promesa, la hemos retornado porque si no, no obtendríamos resultado y lo hemos metido todo dentro de una función que empieza con <em>async</em>. Ahora vamos a usarlo como si de una promesa normal se tratase</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">asyncPromise().then((result) => console.log(result))
</code></pre></div>
<p>Bien ya tenemos todo, ahora vamos a ejecutarlo<br>
<img srcset="/assets/images/2017/10/Captura-de-pantalla-2017-10-10-a-las-21.35.32.png" alt="Don't stop the party: Node JS(XII) Promesas"/></br></p>
<p>Como habréis podido comprobar nos ha aparecido el log indicando que empieza y a los 2 segundos nos ha mostrado el resultado como si de una promesa normal se tratase. Este tipo de estructura realmente nos puede ahorrar el uso de callbacks de finalización o similar. Esto es solo un ejemplo de lo que se puede hacer con estas opciones "nuevas" de node, pero se puede usar de otras muchas maneras, el límite lo ponéis vosotros de como usar esto.</p>
<p>Creo que por el momento vamos a dejar las promesas (o lo relacionado con ellas) aquí, en algún otro momento volveremos a trastear con ellas pero creo que hemos visto más o menos como se tienen que usar y en que nos pueden ayudar. Creo que solo me quedaría un mini-post más de extras de Node y nos pondríamos ya con MongoDB.</p>
<p>Nos veeeemosssss un abrazooorrrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(XI) Autenticación]]></title><description><![CDATA[En este post vamos a centrarnos en algunas de las posibilidades de
implementación de autenticación en Node, concretamente hablaremos de lo que se
conoce como Basic Auth y de JSON Web Token.
Basic Auth
Este sistema de autenticación es el más sencillo de todos, y a su vez no de lo
más seguro, pero puede que para un sistema sencillo o alguna aplicación interna
pueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero
si entras....pues bienvenido pásalo bien ;) ).
Vamos a con]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-x-templates-o-vistas-2/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f37</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 10 Oct 2017 08:00:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-6.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-6.jpg" alt="Don't stop the party: Node JS(XI) Autenticación"/><p>En este post vamos a centrarnos en algunas de las posibilidades de implementación de autenticación en Node, concretamente hablaremos de lo que se conoce como <strong>Basic Auth</strong> y de <strong>JSON Web Token</strong>.</p>
<h3 id="basicauth">Basic Auth</h3>
<p>Este sistema de autenticación es el más sencillo de todos, y a su vez no de lo más seguro, pero puede que para un sistema sencillo o alguna aplicación interna pueda servirnos (en plan....bueno voy a intentar que no entre todo el mundo pero si entras....pues bienvenido pásalo bien ;) ).<br>
Vamos a configurar por ejemplo nuestra ruta con <em>heros</em>, la que está en el fichero <em>ninjas.js</em> para que nos solicite un usuario y contraseña.</br></p>
<p>Lo primero de todo como es habitual en Node, usaremos <em>npm</em> para instalar el módulo necesario</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install basic-auth --save
</code></pre></div>
<p>A continuación lo que hacemos es <em>requerir</em> el módulo como siempre y lo siguiente en el middleware que queramos usamos lo que hemos <em>requerido</em> y le pasamos la request. Esto lo que hará será buscar datos de usuario y contraseña en ella.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Con esto importamos el módulo
const auth = require('basic-auth');
</code></pre></div>
<p>Y en nuestro middleware</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">router.get('/heros', function(req, res, next) {
const userLogin = auth(req);
</code></pre></div>
<p>Ahora si lo probaramos esto no haría nada, tenemos que añadirle algunas cosas más.<br>
Tenemos que hacer que nos solicite usuario y contraseña, para hacer esto tenemos que responder a nuestro cliente desde nuestro middleware con un valor espécifico en la cabecera y ya de paso para hacerlo bien le ponemos el código de estado pertinente (401 en este caso). Pero claro esto no es tan automático como podemos pensar, necesiteamos controlar si ya nos ha pasado usuario y contraseña en nuestra constante <strong>userLogin</strong>, con todo esto de momento nuestro código sería el siguiente</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">router.get('/heros', function(req, res, next) {
const userLogin = auth(req);
if (!userLogin) {
res.set('WWW-Authenticate', 'basic realm=Authorization Required');
res.send(401);
return;//Esto para que no continue la ejecución del middleware
}
res.json({ninja:"Somos un monton de ninjas autenticados" })
});
</code></pre></div>
<p>Si ahora lo probamos tendríamos esto<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.33.17.png" alt="Don't stop the party: Node JS(XI) Autenticación"><br>
Como veis nos pide usuario y contraseña pero claro ahora mismo pongamos lo que pongamos nos dejará pasar, tenemos que comprobar el usuario y contraseña de alguna forma. En un principio esto lo ideal sería tener una base de datos, un fichero o similar para comprobar tanto usuario como contraseña, en nuestro caso no tenemos implementado nada de esto por lo que de momento lo que haremos será comprobarlo directamente en el código, pero tener en cuenta que en este punto lo que haríamos sería comprobar en algún lado que los datos son correctos</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">router.get('/heros', function(req, res, next) {
const userLogin = auth(req);
if (!userLogin) {
res.set('WWW-Authenticate', 'basic realm=Authorization Required');
res.send(401);
return;
}
//Aqui haríamos la comprobación en nuestras base de datos o similar
if (userLogin.name !== 'ninja' || userLogin.pass !== '1234' ){
res.set('WWW-Authenticate', 'basic realm=Authorization Required');
res.send(401);
return;
}
res.json({ninja:"Somos un montón de ninjas autenticados" })
});
</code></pre></div>
<p>Ahora ya si lo probamos solo funcionará si introducimos ese usuario y contraseña<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-30-at-12.39.40.png" alt="Don't stop the party: Node JS(XI) Autenticación"><br>
Como veis es bastante simple, veamos ahora como podemos hacer esto un poco más elegante, no creo que sea lo mejor hacer este código en todos los middleware que necesitemos (bueno si es general para toda la aplicación solo necesitamos ponerlo en el <strong>app.js</strong> y crear un middleware que responda a todas las request, pero ese no creo que sea el escenario en general).<br>
Vamos a crear nuestro propio módulo para gestionar esto, primero creamos una carpeta <em>lib</em> que sera la que tendrá las librerías/módulos que creemos o importemos y no lo hagamos con npm. Creamos un fichero <strong>auth.js</strong> y lo que haremos será <em>exportar</em> el <em>callback</em> al que respondería un middleware</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
const auth = require('basic-auth');
module.exports = (req, res, next) => {
const userLogin = auth(req);
if (!userLogin) {
res.set('WWW-Authenticate', 'basic realm=Authorization Required');
res.send(401);
return;
}
//Aqui haríamos la comprobación en nuestras base de datos o similar
if (userLogin.name !== 'ninja' || userLogin.pass !== '12345' ){
res.set('WWW-Authenticate', 'basic realm=Authorization Required');
res.send(401);
return;
}
next();//Para que continue con el siguiente middleware
};
</code></pre></div>
<p>Básicamente he puesto el mismo código que habíamos añadido antes, solo que al final le hemos puesto un <strong>next()</strong> para que continue con el siguiente middleware que coincida.<br>
Ahora vamos a módificar nuestra ruta <em>ninjas</em> para que use esto</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict'
var express = require('express');
var router = express.Router();
const auth = require('../lib/auth.js');
/* GET home page. */
router.get('/heros', auth, function(req, res, next) {
res.json({ninja:"Somos un montón de ninjas autenticados" })
});
module.exports = router;
</code></pre></div>
<p>Hemos importado nuestro módulo y simplemente se lo hemos pasado como primer handler del middleware. <strong>A un middleware le podemos pasar todos los handlers que queramos y se irán ejecutando uno detrás de otro según vayan terminando</strong>.<br>
Si ahora lo probáis debería funcionaros igual que antes, probar a cambiar la contraseña porque seguramente el navegador haya almacenado los datos que habéis introducido anteriormente.<br>
Bueno en cuanto a este método de autenticación poco más merece que miremos, es bastante sencillo y pueden existir otro tipo de implementaciones pero este sería el funcionamiento típico.</br></br></p>
<h3 id="jsonwebtoken">JSON Web Token</h3>
<p>Y, ¿qué es JSON Web Token?... básicamente es una forma de tener una sesión pero almacenandola en el cliente, lo que aligera un poco la gestión de esto por parte del backend y como su nombre indica lo hacemos en formato JSON.<br>
El proceso sería el siguiente. El usuario se autentica con su usuario y contraseña, el cual se comprueba de alguna forma (BBDD, fichero, etc...), el backend una vez que confirma los datos le devuelve al usuario un <em>token</em>. A partir de entonces todas las peticiones HTTP del usuario deben ir acompañadas de este token(cabecera, queryString...). El token se almacena en el lado del cliente de alguna forma(<em>sessionStorage o localStorage</em> por ejemplo), lo que hace que no tenga que mantener esta información el backend, lo que convierte todo en bastante más escalable. El <em>Token</em> es una firma cifrada que el backend descifra y verifica al recibirla lo que permite confirmar la identidad del usuario.<br>
Este tipo de autenticación nos permite utilizar el mismo tipo de autenticación para todos nuestros desarrollos (Web, Android, IOS,....) solo es necesario hacer la gestión pertinente del token. También nos provee de algo más de seguridad, ya que no usa cookies para mantener información de usuario se pueden evitar ciertos tipos de ataques que manipulen la sesión y además podemos hacer que el token expire cada cierto tiempo lo que nos provee de otra capa más de seguridad.<br>
Vamos a hablar un poco del token que recibimos para que entendamos un poco que información lleva. Este de aqui será un token tipo</br></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0.qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4
</code></pre></div>
<p>Si os fijáis bien esta compuesto por tres strings separados por puntos, hablemos un poco de cada uno</p>
<p><strong>1º Header</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
</code></pre></div>
<p>Esto básicamente indica el tipo de token y el algoritmo usado para codificar, normalmente es <em>HMAC SHA256</em>. Descodificado sería algo similar a esto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">{
"alg": "HS256",
"typ": "JWT"
}
</code></pre></div>
<p><strong>2º Payload/Data</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NDk4NTEsImV4cCI6MTUwNzAyMjY1MX0
</code></pre></div>
<p>La segunda parte tiene datos extra que indicamos nosotros desde el backend que se guarden, ya sea para recomprobar en el backend o cualquier otra cosa. Este <em>payload</em> a parte de la información que queramos nosotros guardar, tiene lo que se conoce como <em>claims</em>, son atributos propios que definen el token(<a href="http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#RegisteredClaimName">aqui</a> más en detalle), tiene mínimo 2:</p>
<ul>
<li><em>iat</em>: La fecha en la que se creó el token.</li>
<li><em>exp</em>: La fecha de expiración del token. Esto normalmente lo indicamos nosotros desde el backend.</li>
</ul>
<p>Descodificado este tendría:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">{
"user": "ninja",
"iat": 1506849851,
"exp": 1507022651
}
</code></pre></div>
<p><strong>3º Firma/Signature</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">qVSS9iQAyIQzjlp4uCyiJUOGSgXMSbmZUAJ7hQncco4
</code></pre></div>
<p>Esta última parte es la que realmente comprobamos en el backend, esta compuesta de los 2 strings anteriores codificados en <em>BASE64</em> junto con una <em>clave secreta</em> que indicamos nosotros en el backend, por lo que si lo que descodifica en este punto es igual que lo anterior da por sentado que es correcto.<br>
Descodificado sería:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
Secret KEY
)
</code></pre></div>
<p><em>Secret KEY</em> es la clave secreta que hemos usado para codificar. Podemos comprobar este token completo en la pagina oficial de <a href="https://jwt.io/">JWT.io</a> solo es necesario copiar el token completo en la parte donde pone <em>ENCODED</em> y poner la clave secreta <em>"Secret KEY"</em> en la zona donde pone <em>VERIFY SIGNATURE</em>.<br>
Bueno ya hemos visto un poco de teoría sobre de que esta compuesto el token, ahora vamos a implantar <em>JWT</em> en <em>Node</em> para que veamos un ejemplo de como se hace implanta.</br></p>
<p>Lo primero de todo como siempre es instalar el módulo de <em>jsonwebtoken</em> con npm.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install jsonwebtoken --save
</code></pre></div>
<p>Una vez instalado, vamos a crearnos otra <em>ruta</em> para hacer el login (así repasamos un poco), para ello en la carpeta <em>routes</em> creamos el fichero <em>login.js</em> con este contenido</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var express = require('express');
var router = express.Router();
const jwt = require('jsonwebtoken')
router.post('/', function(req, res, next) {
const user = req.body.user;
const pass = req.body.pass;
if (!user){
return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});
}
if (!pass){
return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});
}
//Aqui lo suyo es que comprobaramos con una base de datos o fichero el usuario y contraseña
if (user !== 'ninja' || pass !== '1234'){
return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});
}
//La clabe secreta que pone Secret KEY debería estar en un fichero de configuración o deberíamos usar variables de entorno para que no este puesta directamente
const token = jwt.sign({user: user},'Secret KEY',{expiresIn: "2 days"});
res.json({sucess: true, token: token});
});
module.exports = router;
</code></pre></div>
<p>Como siempre <em>requerimos</em> express e instanciamos <em>router</em>, como extra <em>requerimos</em> nuestro nuevo módulo <strong>jsonwebtoken</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">const express = require('express');
const router = express.Router();
const jwt = require('jsonwebtoken')
</code></pre></div>
<p>Hacemos que este nuevo middleware responda a peticiones <em>post</em>, necesario ya que mandaremos la información en el body, y extraemos el usuario y contraseña para comprobarlos(se podría hacer en el cliente que la contraseña se codificara de alguna forma para mayor seguridad pero eso esta fuera de lo que queremos ver con Node)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">router.post('/', function(req, res, next) {
const user = req.body.user;
const pass = req.body.pass;
</code></pre></div>
<p>Ponemos comprobaciones típicas, por si el usuario o contraseña estan vacios y en nuestro caso que usuario y contraseña están bien, pero recordar que esto realmente se debería comprobar en una base de datos o similar, esto es solo para agilizar el desarrollo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> if (!user){
return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid user'});
}
if (!pass){
return res.status(401).json({sucess: false, error: 'Auth failed. We need a valid pass'});
}
if (user !== 'ninja' || pass !== '1234'){
return res.status(401).json({sucess: false, error: 'Auth failed. Invalid user or password'});
}
</code></pre></div>
<p>Ahora tenemos donde creamos el token</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">const token = jwt.sign({user: user},'Secret KEY',{expiresIn: "2 days"});
</code></pre></div>
<p>Le hemos puesto un <em>payload/data</em> en formato JSON(da menos problemas con este formato) que contiene el usuario. Luego le hemos indicado la clave secreta para componer el hash <em>Secret KEY</em>, **IMPORTANTE esto no debería estar así deberíamos ponerlo en un fichero de configuración o en las variables de entorno de nuestro backend, para extraerlo con <em>process.env...</em> **. Por último le hemos indicado el tiempo de expiración de nuestro token, esto tiene varios formatos podéis verlos en la página de npm sobre <a href="https://www.npmjs.com/package/jsonwebtoken">JSON Web token</a>.<br>
Por último le devolvemos al cliente el token que hemos generado para que lo use</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.json({sucess: true, token: token});
</code></pre></div>
<p>Ya tenemos nuestra nueva ruta creada, la indicamos en el <em>app.js</em>, importamos la nueva ruta, por ejemplo debajo de la de ninjas que creamos anteriormente</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var ninjas = require('./routes/ninjas');
var login = require('./routes/login');
</code></pre></div>
<p>Y le indicamos a express que la use(debajo de la de ninjas por ejemplo)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use('/ninjas',ninjas);
app.use('/login',login);
</code></pre></div>
<p>Voilá ya lo tenemos ahora vamos a probarlo, lo mejor sería hacerlo con un software tipo <em>POSTMAN</em> o similar que nos permite personalizar como hacemos las peticiones HTTP.<br>
Como hemos configurado le pasamos en el <em>body por post</em> el usuario y contraseña.<br>
<img srcset="/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.48.36.png" alt="Don't stop the party: Node JS(XI) Autenticación"><br>
Como veis tenemos nuestro token jejejeje, relativamente sencillo ¿verdad? Si cambiamos la contraseña veréis como nos devuelve algún tipo de 401<br>
<img srcset="/assets/images/2017/10/Screen-Shot-2017-10-01-at-12.50.30.png" alt="Don't stop the party: Node JS(XI) Autenticación"/></br></br></img></br></br></p>
<p>Bueno ya tenemos el token.....pero nos falta algún sitio para usarlo, ¿no?...pues vamos a por ello.<br>
Al igual que hicimos arriba con <em>Basic Auth</em> vamos a crearnos un módulo para gestionar la verificación del login. En la carpeta <em>lib</em> creamos el fichero <em>authJWT.js</em> y ponemos lo siguiente</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">const jwt = require('jsonwebtoken');
module.exports = function(req,res,next) {
const token = req.query.token;
if (token){
jwt.verify(token,'Secret KEY',(err,decoded) => {
if (err){
console.log(decoded)
return res.status(401).json({success: false, error: 'Failed to authenticate token'});
} else {
console.log('Decoded',decoded);
next();
}
});
}else{
return res.status(403).json({success: false, error: 'No token provided'})
}
}
</code></pre></div>
<p>El código es bastante simple, recibimos el token por <em>queryString</em>, y lo verificamos con <strong>jwt.verify</strong> pasandole también la <em>clave privada</em> que hemos usado y una vez comprobado saltaría el callback con el error o con el payload descodificado. <strong>Recordar clave secreta aqui kaka, tiene que estar en fichero de configuración o en variable de entorno</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">jwt.verify(token,'Secret KEY',(err,decoded) => {
</code></pre></div>
<p>Le he puesto un <em>console.log</em> para que veáis lo que descodifica si todo va bien o da error.<br>
Por último tenemos que hacer que algún middleware lo use de alguna manera. En este caso vamos a cambiar el que usamos con <em>Basic Auth</em> y usamos el nuevo con <em>JWT</em>. Nos vamos a <em>ninjas.js</em> y ponemos lo siguiente</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict'
var express = require('express');
var router = express.Router();
//const auth = require('../lib/auth.js');
const authJWT = require('../lib/authJWT.js');
router.get('/heros', authJWT, function(req, res, next) {
res.json({ninja:"Somos un monton de ninjas autenticados" })
});
module.exports = router;
</code></pre></div>
<p>Comentamos lo que pertenecia a <em>basic-auth</em> y hacemos lo mismo que hicimos antes pero con <em>JWT</em> y ya lo tendríamos, vamos a probarlo para ello el token que nos ha devuelto antes se lo pasamos como <em>queryString</em></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://localhost:3000/ninjas/heros?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibmluamEiLCJpYXQiOjE1MDY4NTUzNTAsImV4cCI6MTUwNzAyODE1MH0.RS-ow1UqTz66l5X26rpKw5qB-1gX31t8_ycNgIkdUuE
</code></pre></div>
<p>Y si todo va bien veremos esto<br>
<img srcset="/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.04.png" alt="Don't stop the party: Node JS(XI) Autenticación"><br>
y si por algún motivo el token no es correcto<br>
<img srcset="/assets/images/2017/10/Screen-Shot-2017-10-01-at-13.09.48.png" alt="Don't stop the party: Node JS(XI) Autenticación"><br>
Bueno como hemos visto usar <em>JSON web Token</em> es relativamente sencillo, en este caso no hemos usado base de datos pero lo ideal seria tener los usuarios y contraseñas almacenados en una base de datos, con la contraseña codificada con algún tipo de hash por supuesto, y hacer las comprobaciones con ellos, no tenerlos en nuestro código puestos a mano.<br>
Como extra comentaros que casi todos los métodos de autenticación con token (login con terceros como Google, Facebook, OAuth, Azure o AWS por ejemplo) suelen funcionar de forma similar, es decir un token que almacenamos y pasamos en cada petición normalmente en el <strong>header</strong> con un nombre tipo <em>x-access-token</em>, <em>authorization</em> o similar.</br></br></img></br></br></img></br></p>
<p>Y hasta aquí la parte de autenticación en el siguiente post y el último por el momento de esta serie de Node (Lo siguiente será mezclar con MongoDB) hablaremos de <strong>Promesas</strong> que aunque no es propio de NodeJS, es más de JS creo que es útil que las repasemos y también veremos como poner nuestro proceso de Node en <strong>cluster</strong> para aumentar el rendimiento con un gran númeo de peticiones. Luego empezaré una linea nueva de post donde hablaremos de <strong>MongoDB</strong> y ya de paso lo integraremos con Node.</p>
<p>Nos veeeemossss un abrazooorrrrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(X) Templates o Vistas]]></title><description><![CDATA[Ahora le toca el turno a las vistas o templates, aunque realmente este tema es
muy amplio porque express admite multitud de engines de templates distintos. En
la documentación oficial
[https://github.com/expressjs/express/wiki#template-engines] tenéis todos los
que soporta y como se usan, veremos ejemplos con ejs porque es muy típico pero
realmente podéis usar el que queráis.
Comentaros que a mi personalmente no me gusta mucho renderizar cosas en servidor
para servirlas al cliente ya que aumenta]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-x-templates-o-vistas/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f36</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 05 Oct 2017 08:00:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-4-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-4-1.jpg" alt="Don't stop the party: Node JS(X) Templates o Vistas"/><p>Ahora le toca el turno a las vistas o templates, aunque realmente este tema es muy amplio porque <strong>express</strong> admite multitud de <em>engines</em> de templates distintos. En la <a href="https://github.com/expressjs/express/wiki#template-engines">documentación oficial</a> tenéis todos los que soporta y como se usan, veremos ejemplos con <em>ejs</em> porque es muy típico pero realmente podéis usar el que queráis.<br>
Comentaros que a mi personalmente no me gusta mucho renderizar cosas en servidor para servirlas al cliente ya que aumentas la carga de trabajo del servidor, prefiero usar Node+Express como API Rest y para las vistas usar directamente <strong>AngularJS</strong>, <strong>ReactJS</strong> o similar pero al final depende un poco del proyecto o aplicación que estemos realizando, si es una página simple, casi como las que hemos visto de ejemplo, usamos los templates y ale a correr.<br>
Bueno después de quejarme un poco vamos a continuar....como he comentado trabajaremos un poco con <strong>ejs</strong> y para ello lo primero que tenemos que hacer es instalar el engine.</br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install ejs --save
</code></pre></div>
<p>Recordad usamos <strong>--save</strong> para que al instalar el módulo lo indique también en el <strong>package.json</strong> y poder llevar control de versiones (y ya de paso si movemos la app que lo instale directamente)<br>
Antes de continuar, os cuento, nosotros vamos a modificar nuestro proyecto de express actual para cambiar el <em>engine</em> pero si de primeras ya sabéis que váis a usar un engine en concreto, si recordáis se lo podíamos indicar a <strong>express_generator</strong> para que configure él directamente, si probáis el comando:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">express -h
</code></pre></div>
<p>veréis las opciones que tenemos<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.03.31.png" alt="Don't stop the party: Node JS(X) Templates o Vistas"><br>
Aún así no penséis que cambiar de uno a otro es muy difícil solo tenemos que saber que caracteriza a cada uno, o más bien como se compone cada uno. En el caso de <strong>ejs</strong> es que realmente tu realizas la composición sobre código HTML, supongo que es una de las claves de su aceptación, básicamente es lo mismo que ya se estaba haciendo desde hace años pero con vitaminas.</br></img></br></p>
<p>El primer cambio que haremos una vez instalado es cambiar el <em>engine</em> en el <strong>app.js</strong>, para ello vamos a cambiar la línea</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.set('view engine', 'jade');
</code></pre></div>
<p>por esta otra (solo cambiando jade....superdifícil)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.set('view engine', 'ejs');
</code></pre></div>
<p>Ya tenemos el primer paso, lo siguiente que haremos será cambiar la vista <strong>index</strong> por ejemplo(solo cambiaremos una para que veáis de que va). Priemo eliminamos el <strong>index.jade</strong> de la carpeta <em>views</em> y creamos otro que sea <strong>index.ejs</strong>. Una vez creado vamos a empezar por un código simple de HTML(mu feo lo sé es para probar solo)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html>
<head>
<h1>NinjaTitle</h1>
</head>
</html>
</code></pre></div>
<p>Esto nos muestra ya lo siguiente<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.43.35.png" alt="Don't stop the party: Node JS(X) Templates o Vistas"><br>
Ya funciona. Ahora vamos a prepararlo para que use la variable <em>title</em> que le pasabamos desde el middleware.</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html>
<head>
<h1>NinjaTitle</h1>
</head>
<body>
<p>Bienvenidos a vuestro template ejs <%= title %></p>
</body>
</html>
</code></pre></div>
<p>Si os fijáis la variable esta puesta directamente entre <strong><%= %></strong>, fácil ¿verdad?. Ahora vamos a probarlo, recordar que teníamos configurado el middleware para que usara los datos recibidos de la <em>query string</em>, por lo que la URL debería ser algo similar a</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://localhost:3000/?title=Ninjas
</code></pre></div>
<p>Y nos debería mostrar algo similar a<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-22-at-21.50.14.png" alt="Don't stop the party: Node JS(X) Templates o Vistas"><br>
Voilá supersencillo. Ahora veamos alguna cosa más que podemos hacer con <strong>ejs</strong>.<br>
En el ejemplo hemos usado <%= %> para trabajar con variables, pero claro si queremos poner código HTML como variable, ¿funcionaría? Veamos que pasa.<br>
Cambiamos la variable title que le mandamos a la vista, en nuestro <strong>index.js</strong> cambias <strong>res.render</strong> por</br></br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.render('index', { title: '<h2>' + newTitle + '</h2>' });
</code></pre></div>
<p>Y ahora veamos el resultado<br>
<img srcset="/assets/images/2017/09/html_tags.PNG" alt="Don't stop the party: Node JS(X) Templates o Vistas"><br>
Ups!!! nos aparace todo literal, eso es porque con <strong><%= %></strong> básicamente conseguimos que nos transforme todo a literal(en este caso un string), pero <strong>ejs</strong> está preparado para esto, solo tenemos que cambiar los tags en nuestro <strong>index.ejs</strong>, básicamente cambiamos el igual por un guión y listo</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html>
<head>
<h1>NinjaTitle</h1>
</head>
<body>
<p>Bienvenidos a vuestro template ejs <%- title %></p>
</body>
</html>
</code></pre></div>
<p>Ahora ya tendríamos algo similar a esto<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-26-at-21.44.21.png" alt="Don't stop the party: Node JS(X) Templates o Vistas"><br>
Acabamos de ver como podemos pasarle estructuras de HTML directamente a la vista, pero todavía podemos hacer más cosas interesantes. Una de las ventajas de <strong>ejs</strong> es que podemos usar código javaScript directamente en la vista, vamos a ver algunos ejemplos<br>
Empecemos por ver como podríamos hacer un condicional, cambiémos nuestro <strong>index.ejs</strong> por esto</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html>
<head>
<h1>NinjaTitle</h1>
</head>
<body>
<p>Bienvenidos a vuestro template ejs <%- title %></p>
<% if (title === 'Ninjas'){ %>
<p>Somos Ninjas</p>
<%}else{%>
<p>Te has equivocadooooo</p>
<%}%>
</body>
</html>
</code></pre></div>
<p>Y que no se nos olvide cambiar en nuestro <strong>index.js</strong> la línea de <strong>render</strong> por</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.render('index', { title: newTitle});
</code></pre></div>
<p>Solo es quitarle los <em>tags</em> HTML.<br>
Ahora vamos a probarlo, pongamos por ejemplo esto en la url<br>
<strong><a href="http://localhost:3000/?title=Superman">http://localhost:3000/?title=Superman</a></strong><br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.12.54.png" alt="Don't stop the party: Node JS(X) Templates o Vistas"><br>
Vemos como al no cumplir la condición sale la segunda opción, ahora probemos con nuestro <em>title=Ninjas</em><br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.15.15.png" alt="Don't stop the party: Node JS(X) Templates o Vistas"><br>
Por último vamos a probar a trabajar con un <em>array</em> de elementos. Creemos lo primero nuestro objeto array en <strong>index.js</strong>, cambiando el ya conocido <strong>res.render</strong> por</br></img></br></br></img></br></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.render('index', {
title: newTitle,
superHeros: [{name: 'Dr. Manhattan'},{name: 'Superman'},{name: 'El Comendiante'}]
});
</code></pre></div>
<p>Ya tenemos nuestro array de elementos, ahora hagamos que la vista trabaje con ellos, en <strong>index.ejs</strong> añadimos lo siguiente</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html>
<head>
<h1>NinjaTitle</h1>
</head>
<body>
<p>Bienvenidos a vuestro template ejs <%- title %></p>
<% if (title === 'Ninjas'){ %>
<p>Somos Ninjas</p>
<% superHeros.forEach(function(hero){ %>
<p><%= hero.name %></p>
<%})%>
<%}else{%>
<p>Te has equivocadooooo</p>
<%}%>
</body>
</html>
</code></pre></div>
<p>Si os fijáis hemos recorrido directamente el objeto <strong>superHeros</strong> y hemos mostrado la propiedad <strong>name</strong> de cada uno. Veamos lo que pasa cuando usamos <strong>title=Ninjas</strong><br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-27-at-08.27.49.png" alt="Don't stop the party: Node JS(X) Templates o Vistas"><br>
Voilá, como véis es relativamente sencillo utilizar templates ejs, esto ha sido solo una pequeña muestra de como podemos ir trabajando con ellos pero las posibilidades son infinitas (y también recordar que tenemos multitud de engines distintos).</br></img></br></p>
<p>Hasta aquí lo que quería comentar sobre los templates, en los siguientes post veremos como gestionar autenticación en nuestra API, uso de Promesas....y varias cosas más, nos veeemossss</p>
<p>Un abrazooorrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(IX) Rutas o Middlewares]]></title><description><![CDATA[Vamos a profundizar un poco en esto de las rutas, que es una de las partes
centrales de express(y yo diría de Node casi).
Las rutas es lo que hemos llamado anteriormente métodos (el get que configuramos
para probar), y como ya comentamos y vimos en la documentación oficial de
express, tenemos lo siguiente
app.method(urlPath,handler)
Siendo:
* app: Ya vimos que es una instancia de express.Esta parte puede ser tambien
router, ya veremos porque.
* method: * GET: Se usa para pedir datos, y]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-ix-rutas/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f35</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 03 Oct 2017 07:45:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-5.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-5.jpg" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"/><p>Vamos a profundizar un poco en esto de las rutas, que es una de las partes centrales de express(y yo diría de Node casi).<br>
Las rutas es lo que hemos llamado anteriormente métodos (el <strong>get</strong> que configuramos para probar), y como ya comentamos y vimos en la documentación oficial de express, tenemos lo siguiente</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.method(urlPath,handler)
</code></pre></div>
<p>Siendo:</p>
<ul>
<li><strong>app:</strong> Ya vimos que es una instancia de express.Esta parte puede ser tambien <strong>router</strong>, ya veremos porque.</li>
<li><strong>method:</strong>
<ul>
<li><strong>GET:</strong> Se usa para pedir datos, y siempre que se le llame tiene que devolver lo mismo(siempre que la petición se haga de la misma forma)</li>
<li><strong>POST:</strong> Para crear algo, un objeto de nuestra app</li>
<li><strong>PUT:</strong> Se usa para actualizar datos u objetos existentes.</li>
<li><strong>DELETE:</strong> Elimina datos u objetos existentes y al igual que el get siempre tiene que darnos el mismo resultado.</li>
<li><strong>ALL:</strong> Con all, express aceptaría cualquiera de los anteriores, siempre y cuando el path coincida. Un posible uso sería para verificar credenciales si por ejemplo un token de sesión ha caducado y el usuario puede estar haciendo cualquier cosa, es decir, usando cualquiera de los otros métodos.</li>
</ul>
</li>
<li><strong>urlPath:</strong> Será el path que si coincide con la petición que ha recibido Node ejecutará su <strong>handler</strong> asociado</li>
<li><strong>handler:</strong> Es el callback o función que se ejecuta si coincide el path.</li>
</ul>
<p>Un detalle <strong>importante</strong> es que se comprueban las coincidencias de rutas en el orden que están escritas por lo que puede ser una buena opción si por ejemplo queremos comprobar si un usuario tiene permiso para acceder a cierta ruta o path.</p>
<p>Otro tipo de ruta o middleware es la de <strong>ficheros estáticos</strong> como pueden ser imágenes,css o ficheros javascript, ya comenté un poco en el post anterior como era ya que por defecto la carpeta <strong>public</strong> estaba configurada como tal, veamoslo un poco en detalle</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use(express.static(path.join(__dirname, 'public')));
</code></pre></div>
<p>Con esto lo que le estamos indicando a express y a node con este middleware es que todo lo que este en la carpeta <strong>public</strong> será servido como estático, ojo teniendo que usar la estructura de carpetas existentes, me refiero a que si debajo de public tenemos una carpeta <em>images</em> el path deberia ser <strong>urlRaiz/images/imagen.jpg</strong>. Vamos a comprobarlo con el fichero <strong>css</strong> que nos crea por defecto <em>express generator</em>, que en este caso esta dentro de la carpeta <em>stylesheets</em> y tiene el nombre <em>style.css</em>, entonces como hemos comentado la ruta sería (con nuestro proyecto iniciado claro está)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://localhost:3000/stylesheets/style.css
</code></pre></div>
<p>Lo que nos devolvería el fichero css en el navegador<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-19-at-08.51.39.png" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"/></br></p>
<p>También podemos indicarle a express que nos sirva los estáticos a través de un path o ruta virtual que nosotros le indiquemos, en lugar desde la ruta raiz. Si ponemos esta línea en el fichero <strong>app.js</strong> de nuestro proyecto (cambiandola por la que nos servía estáticos antes)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use('/ninja_static',express.static(path.join(__dirname, 'public')));
</code></pre></div>
<p>entonces nuestra url cambiaría a</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://localhost:3000/ninja_static/stylesheets/style.css
</code></pre></div>
<p>Esto es muy útil si por ejemplo tenemos una estructura de carpetas de estáticos muy larga y queremos realemente acortar las url, podríamos por ejemplo cambiarlo por</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use('/ninjacss',express.static(path.join(__dirname, 'public/stylesheets')));
</code></pre></div>
<p>Lo que nos convierte la url a</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://localhost:3000/ninjacss/style.css
</code></pre></div>
<p>Como véis podemos gestionar nuestras rutas como queramos para que sea más cómodo trabajar con ellas.</p>
<h3 id="rutasmiddlewaresconparmetros">Rutas/Middlewares con parámetros</h3>
<p>Hasta ahora habíamos visto siempre como trabajar con rutas digamos <em>estáticas</em> pero claro ninguna API es nunca tan simple, generalmente en la URL pasamos información para recibir un elemento específico, imaginemos por ejemplo que estamos creando una API que nos devuelva información sobre todos los superhéroes/villanos de los comics del mundo, ¿cuántos podrían ser? Miles como mínimo, lo que supondría tener que hacer una API con miles de <strong>middlewares</strong> ¿no?...por suerte no es necesario ya que sería algo inviable, ningún servicio aguantaría eso, lo que hacemos es que nuestro <em>middleware</em> reciba parámetros por ejemplo en la url, con este estilo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://heroapi.com/hero/57
</code></pre></div>
<p>o este por ejemplo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://heroapi.com/hero?name=batman
</code></pre></div>
<p>Tenemos varias formas de hacerlo, para finalmente buscar la información usando ese parámetro, todo en el mismo <em>middleware</em>.<br>
En general tenemos cuatro formas de hacerlo:</br></p>
<ul>
<li>En la propia ruta: /hero/57</li>
<li>Usando <em>query string</em>: /hero?name=batman, se conoce <em>query string</em> a lo que está destrás de <strong>?</strong> y son elementos de <em>variable=valor</em></li>
<li>Puede ir en el cuerpo(body) de la petición, esto generalmente se usa para peticiones de tipo POST o PUT, ya que al almacenar/actualizar solemos enviar muchos datos y pasarlo por <em>query string</em> puede ser casi imposible.</li>
<li>Otra opción puede ser la cabecera, aunque esta opción exista simplemente porque podemos acceder a la cabecera desde el middleware, pero no se usa para datos triviales (como buscar un héroe), si no para datos como token de autenticación, formatos y cosas así.</li>
</ul>
<h4 id="enlaruta">En la ruta</h4>
<p>Empecemos con un ejemplo con usando la ruta, nos vamos a nuestro proyecto de ejemplo <strong>ninja_project</strong> y vamos a modificar la ruta del <strong>index.js</strong> poniéndole un parámetro para cambiar el título. Quedaría así:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/:title', function(req, res, next) {
var newTitle = req.params.title
res.render('index', { title: newTitle });
});
module.exports = router;
</code></pre></div>
<p>Como véis a la ruta le hemos puesto <strong>:title</strong> y luego simplemente hemos sacado esa información de los parámetros (params) de la petición (request).<br>
Si ejecutamos con <strong>npm start</strong> y probamos por ejemplo con</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://localhost:3000/Ninja
</code></pre></div>
<p>Tendríamos este resultado<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.21.56.png" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"><br>
Usando las rutas como paso de parámetros tenemos varias opciones, para por ejemplo si queremos que el parámetro sea opcional(si probáis sin poner /Ninja os daria un error el ejemplo anterior) ponemos la ruta de esta manera</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">router.get('/:title?', function(req, res, next) {
</code></pre></div>
<p>También es posible usar expresiones regulares para que por ejemplo solo admita números</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">router.get('/:id([0-9]+)', function(req, res, next) {
</code></pre></div>
<p>Y es posible poner varios</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">router.get('/:type(villain|hero)/data/:name)', function(req, res, next) {
</code></pre></div>
<p>Esta aceptaría en type solo <em>villain o hero</em> y en name cualquier cosa.<br>
Las rutas son bastante dinámicas para poder gestionar <em>middlewares</em> de manera más cómoda y segura para nosotros(evitando datos de algún tipo que no queremos recibir).</br></p>
<h4 id="usandoquerystring">Usando query string</h4>
<p>Ahora veamos un ejemplo con la segunda forma, que veréis que es muy parecido.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
console.log(req.query);
var newTitle = req.query.title;
res.render('index', { title: newTitle });
});
module.exports = router;
</code></pre></div>
<p>Hemos vuelto a dejar la ruta o path como estaba y en lugar de obtener el dato de title de los parámetros de la url, lo hacemos con la query y ¿como usamos esto? He puesto también un console.log para que veáis como recibimos los elementos de tipo query string. Simplemente poner</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://localhost:3000/?title=Ninja
</code></pre></div>
<p>Al probar obtendríamos el mismo resultado, y si miráis el log de la consola veréis como recibe los parámetros de la query, como un objeto clave= valor<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.30.05.png" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"><br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-20-at-09.29.57.png" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"/></br></img></br></p>
<h4 id="mtodosderespuesta">Métodos de respuesta</h4>
<p>Hasta ahora hemos estado centrados todo el rato en ala captura de la petición, es decir, en la parte <strong>request</strong> pero ¿que pasa con la respuesta? Vamos a ver algunos de los métodos de respuesta más usados, pero lo mejor es que miréis la <a href="http://expressjs.com/es/4x/api.html#res">documentación</a> que vienen todos y muy bien explicados:</p>
<ul>
<li><strong>res.send</strong>: Lo hemos usado ya en algún ejemplo, responde como puede a lo que le pongas jejeje, funciona bien con buffer, strings, objetos, arrays(estos dos últimos los devolveria como un JSON)...</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.send('Hola Ninjas')
</code></pre></div>
<ul>
<li><strong>res.render</strong>: También lo hemos usado, nos devuelve una página renderizada usando algún template y si acaso usando los parámetros que le pasemos</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.render('index',{title: 'Super Título Ninja'});
</code></pre></div>
<ul>
<li><strong>res.json</strong>: Respuesta específica como JSON</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.json({ name: 'Batman'});
</code></pre></div>
<ul>
<li><strong>res.download</strong>: Devuelve directamente un fichero, este sería el caso típico en el que nos aparece la ventana de <em>guardar</em> en el navegador</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.download('/rutaYNombreFichero.doc','nombreOpcionalDelFichero');
</code></pre></div>
<ul>
<li><strong>res.redirect</strong>: Redireccionando al usuario a otro sitio con un código de estado 302 por defecto(esto se puede cambiar, más abajo lo veremos). En este caso tenemos varias opciones para la redirección.
<ul>
<li>Ruta relativa al root del usuario:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.redirect('/root/path/algo');
</code></pre></div>
<ul>
<li>Url absoluta:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.redirect('http://urlnueva');
</code></pre></div>
<ul>
<li>Pasandole también el código de estado:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.redirect(301,'http://urlnueva');
</code></pre></div>
<ul>
<li>Ruta según el path actual:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.redirect('../ruta/algo')
</code></pre></div>
<ul>
<li>También podemos hacer que vuelva a la página anterior:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.redirect('back')
</code></pre></div>
</li>
</ul>
<p>Si miráis la documentación hay muchos más y todos estos pueden admitir más parámetros, con más opciones de configuración. Comentar que casi todas las opciones de respuesta soportan cambiar el código de estado, solo tenemos que encadenar métodos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">res.status(500).send('Error');
res.status(200).render('index');
</code></pre></div>
<p>Muy cómodo si queremos devolver algún código específico que no sea el de por defecto de cada respuesta.<br>
Poco a poco veremos como van saliendo distintos tipos de respuesta en los ejemplos que vayamos haciendo.</br></p>
<h3 id="creandonuestrapropiaruta">Creando nuestra propia ruta</h3>
<p>Hasta ahora hemos estado trabajando con lo que ya nos había configurado <strong>express</strong>, pero ¿y si queremos crear nuestra propia ruta?¿Cuáles serían los pasos? Bien, pues vamos a verlos.<br>
Lo primero de todo es crearnos un fichero nuevo en la carpeta <em>routes</em>(para mantener el orden), por ejemplo lo voy a llamar <strong>ninjas.js</strong> y de momento le ponemos esto</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict'
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/heros', function(req, res, next) {
res.json({ninjas: "Somos un montón de ninjas"})
});
module.exports = router;
</code></pre></div>
<p>Si os fijáis lo que hacemos es instanciar un <strong>Router</strong>, que es una de las formas de crear rutas para pasarselas a express. A este <em>router</em> le hemos indicado el método a usar, su path y su respuesta y por último lo hemos exportado como si de un módulo se tratara para así poder usarlo en cualquier parte de nuestra aplicación.<br>
Lo siguientes es irnos al <strong>app.js</strong> que, como ya comentamos en su momento, entre otras cosas tiene la instanciación de las rutas, y preparamos la nuestra, para ello lo primero es <em>requerirla</em>, y lo hacemos debajo de las otras</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var index = require('./routes/index');
var users = require('./routes/users');
var ninjas = require('./routes/ninjas');
</code></pre></div>
<p>Ya la tenemos disponible en nuestro <em>app.js</em> pero realmente todavia no le hemos indicado donde tiene que escuchar y que tiene que hacer, para hacerlo buscamos donde ha creado las otras y hacemos lo propio</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use('/', index);
app.use('/users', users);
app.use('/ninjas',ninjas);
</code></pre></div>
<p>Y listo con esto ya tendríamos nuestra propia ruta, como véis es bastante sencillo. Ahora vamos a probarla peeeeero ojo al dato, tenemos que tener en cuenta:</p>
<ul>
<li>La ruta o path que hemos puesto en el <strong>app.use</strong></li>
<li>La ruta o path que hemos puesto en <strong>ninjas.js</strong></li>
</ul>
<p>Esto lo remarco porque realmente esto lo que esta haciendo es escuchar lo primero en el path <strong>/ninjas</strong> y según ese path lo que hace es indicarle al <strong>ninjas.js</strong> que es su turno (en plan enga majete a currar), pero claro este <em>router</em> tiene configurado también su propio path, es decir que a partir del path por el que ha sido convocado en el <em>app.use</em> tiene que cumplir el segundo que en este caso seria <strong>heros</strong>, por lo que la ruta quedariía así</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">http://localhost:3000/ninjas/heros
</code></pre></div>
<p>Y esto nos devolvería un json<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-21-at-09.28.26.png" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"><br>
Una vez que entiendes como funciona, ves que realmente es bastante sencillo configurar y trabajar con las rutas de express.</br></img></br></p>
<p>Durante todo el post, ha estado apareciendo la palabra <strong>middleware</strong> pero , ¿que es exáctamente un middleware? Un <strong>middleware</strong> es un handler o manejador que responde a un tipo de petición o a todas. Básicamente es lo que hemos estado haciendo todo el rato. Veamos algunos detalles de su implementación.<br>
Si os habéis fijado en nuestros middlewares que nos ha creado express, en los parámetros que recibe la función handler, tenemos esto</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function(req, res, next) {
</code></pre></div>
<p>Hemos visto que es <strong>req y res</strong> pero ¿que es next?, básicamente <strong>next</strong> es un método para indicar que continue hasta el siguiente middleware si no queremos terminar la ejecución. Supongamos por ejemplo que queremos comprobar el token de acceso de un usuario o sin ir más lejos si un usuario existe antes de tener acceso a ningún otro middleware. En este caso podríamos crear un middleware que en todas las peticiones compruebe cualquiera de los dos casos y a continuación una vez comprobado simplemente le diríamos que continuará al siguiente middleware para darle acceso a lo que realmente ha solicitado, es decir, acceso al middleware que nos ha mandado como <strong>request</strong>.<br>
Ahora vamos a ver un ejemplo muy sencillito para que se entienda mejor, pero antes comentar que si un middleware <strong>no responde de ninguna forma y no indica explicitamente que vaya al siguiente middleware no saldrá del handler en cuestión y nos dará timeout la petición</strong>. Vamos con el ejemplo, primero comprobemos que nos da timeout, para elloen nuestro <strong>app.js</strong> antes de indicar los middlewares ponemos los siguiente</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use('/', function(req,res,next){
console.log('MIddleware sin respuesta');
});
//Encima de este
app.use('/', index);
</code></pre></div>
<p>Y comprobamos lo que pasa al acceder<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.11.37.png" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"><br>
El log muestra nuestro nuevo middleware pero la ventana se queda a la espera de recibir algo<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.12.01.png" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"><br>
Ahora pongamos el <strong>next</strong> a ver que pasa</br></img></br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use('/', function(req,res,next){
console.log('MIddleware sin respuesta');
next();
});
</code></pre></div>
<p>Como véis en la consola ha pasado por el middleware(2 veces) y ha continuado hasta el siguiente middleware que coincide que es el <strong>index</strong><br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.14.56.png" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"><br>
Y como no hemos pasado en la queryString(que es como lo dejamos antes) solo nos aparece el <strong>welcome</strong><br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-22-at-09.17.10.png" alt="Don't stop the party: Node JS(IX) Rutas o Middlewares"><br>
Pero por lo menos vemos que ha continuado sin problemas.<br>
Importante <strong>no podemos responder a un middleware y pasar al siguiente, lo que sea que queramos hacer tiene que ser al revés</strong>, es decir, no podemos responder 2 veces a la misma petición ya que el cliente no espera más de una respuesta, si en algún momento recibís en consola un log que ponga algo similar a <em>header ya envíado</em> o similar es porque estáis intentando responder dos veces.<br>
Los middlewares podemos separarlos en varios tipos (como concepto de uso):</br></br></br></img></br></br></img></br></p>
<ul>
<li>Tenemos los middlewares a <strong>nivel de aplicación</strong>, es decir, los que ejecutamos en toda actividad de la app, y son los que normalmente deberían estar en el <strong>app.js</strong>. Acabamos de usar uno</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use('/', index);
</code></pre></div>
<ul>
<li>Middleware a <strong>nivel de router</strong>: los que ponemos en la carpeta <strong>routes</strong> y responden a un tipo de petición o path específicos</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {}
</code></pre></div>
<ul>
<li>Middleware <strong>de error</strong>: Estos los ponemos los últimos y como su nombre indica responderan cuando tengamos un error. Si miramos nuestro <strong>app.js</strong> vemos que tenemos uno al final. Se diferencian en que reciben un parámetro más <strong>err</strong>.</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
</code></pre></div>
<p>Normalmente son llamados por nosotros pasándoselo al next, si os fijáis en el <strong>app.js</strong>, justo encima del middleware de error tenemos uno que captura todas las peticiones que no han coincidido y le pasa un mensaje de tipo 404 al middleware de error con <strong>next(err)</strong>(básicamente en cuanto a next le pasemos algo irá al handler de error)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
</code></pre></div>
<ul>
<li>Tenemos más <strong>middlewares oficiales</strong>, que básicamente son los mantenidos en el módulo <strong>connect</strong> que usa express. Podéis encontrar informacíon <a href="https://github.com/senchalabs/connect">aquí</a>.</li>
<li>Por último tenemos otros que llamaríamos <strong>middlewares de terceros</strong>, que son los creados y mantenidos por la comunidad, muchos de ellos aparecen en <a href="http://expressjs.com/en/resources/middleware.html">esta página de express</a></li>
</ul>
<p>Creo que más o menos he comentado casi todo lo importante referente a los middlewares (ha sido un post más largo de lo habitual jejejejje), espero que a partir de ahora podáis hacer los vuestros sin problemas, en el siguiente post veremos un poco los templates y alguna cosa más. Sin mucho más nos veeemossss un abrazoooorrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(VIII) Express generator]]></title><description><![CDATA[En el post anterior vimos como es el trabajo básico con express, creamos una API
que respondía a un método get y nos devolvía un mensaje, con eso más o menos ya
tendríamos que tener una idea de como es el trabajo con node usando otro tipo de
métodos (get,post,put,..)(con la ayuda de la documentación oficial
[http://expressjs.com/es/4x/api.html]), más adelante haremos ejemplos mucho más
complejos, conectándonos a Bases de datos, devolviendo JSON, usando JSON Web
Token para autenticar usuarios....]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-vii-mvc-y-express/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f34</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 28 Sep 2017 08:26:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-4.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-4.jpg" alt="Don't stop the party: Node JS(VIII) Express generator"/><p>En el post anterior vimos como es el trabajo básico con <strong>express</strong>, creamos una API que respondía a un método <strong>get</strong> y nos devolvía un mensaje, con eso más o menos ya tendríamos que tener una idea de como es el trabajo con node usando otro tipo de métodos (get,post,put,..)(con la ayuda de la <a href="http://expressjs.com/es/4x/api.html">documentación oficial</a>), más adelante haremos ejemplos mucho más complejos, conectándonos a Bases de datos, devolviendo JSON, usando JSON Web Token para autenticar usuarios...... pero antes de todo esto vamos a ver como se estructuraría un proyecto de <strong>Node+express</strong> y para ello nos vamos a valer de una herramienta llamada <strong>Express Generator</strong> que básicamente nos crea toda la estructura de carpetas y ficheros básicos que debería tener cualquier proyecto de este tipo.<br>
Lo primero de todo es instalarla con <strong>npm</strong> de manera global ya que no nos serviría como proyecto si no tenemos proyecto......</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install express-generator -g
</code></pre></div>
<p>Una vez instalada podemos hacer</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">express -h
</code></pre></div>
<p>Y vemos que opciones tenemos a la hora de crear nuestro proyecto<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.32.14.png" alt="Don't stop the party: Node JS(VIII) Express generator"><br>
Como véis podemos indicarle varios <strong>engines</strong> html(precesadores de html que gestionan la parte dinámica como datos de base de datos, etc, en el servidor y lo envían ya construido al cliente), css (más o menos mismo concepto) o si queremos añadir un fichero <strong>gitignore</strong> a nuestro proyecto directamente(muy útil por cierto). Cada uno debería elegir las opciones con las que se sienta más cómodo (o las que nos obligue el proyecto).<br>
Para generar un proyecto nuevo es suficiente con escribir <strong>express nombreDeProyecto</strong></br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">express ninja_project
</code></pre></div>
<p>Esto nos creará algunas carpetas con varios ficheros en ellas<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.39.33.png" alt="Don't stop the party: Node JS(VIII) Express generator"><br>
Lo primero miremos el fichero <strong>package.json</strong> para ver que nos ha configurado por defecto. Tendríamos que tener algo similar a esto</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">{
"name": "ninja-project",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "~1.17.1",
"cookie-parser": "~1.4.3",
"debug": "~2.6.3",
"express": "~4.15.2",
"jade": "~1.11.0",
"morgan": "~1.8.1",
"serve-favicon": "~2.4.2"
}
}
</code></pre></div>
<p>Lo primero destacable que vemos es que nos ha creado un <strong>script</strong> llamado <strong>start</strong> donde tiene toda la pinta que es el punto de entrada de nuestra aplicación. A continuación vemos como nos ha seleccionado varias dependecias para ser instaladas, por ejemplo <a href="https://www.npmjs.com/package/body-parser"><strong>body-parser</strong></a> herramienta para parsear los elementos del body de una petición (se encontraría dentro del <strong>request</strong> que vimos en el post anterior, exactamente en <strong>request.body</strong>) o <strong>morgan</strong> el logger que ya vimos.<br>
A continuación tendríamos que instalar las dependencias de nuestro proyecto, por lo que dentro de la carpeta <strong>ninja_project</strong> ejecutamos</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install
</code></pre></div>
<p>Esto nos instala, todas las dependencias que tenemos en nuestro <strong>package.json</strong> y también las dependencias de estas, básicamente un montón de dependencias jejejeje<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-18-at-09.51.54.png" alt="Don't stop the party: Node JS(VIII) Express generator"><br>
Con esto ya tendríamos todo listo para empezar, pero antes veamos un poco que es lo que nos ha configurado, primero de todo nos vamos al fichero por el que comenzaría nuestra aplicación <strong>bin/www</strong>.<br>
En general supongo que al verlo os haréis una idea, resumiendo mucho este fichero es el que nos configura la aplicación para que escuche en algún puerto, veamos un poco como lo hace.</br></br></img></br></p>
<p>Lo primero a tener en cuenta es que <strong>requiere app</strong>, es decir, el fichero <strong>app.js</strong> de la raíz del proyecto. Este fichero básicamente es la instancia de express con algunas de sus configuraciones como son los módulos que va necesitar</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var users = require('./routes/users');
</code></pre></div>
<p>donde se encuentran las vistas y cuál es el <strong>engine</strong> para procesar y mostrar estas vistas como html</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
</code></pre></div>
<p>nivel de logs, la instanciación o configuración de algunos módulos y donde están los ficheros estáticos(en general siempre estan en una carpeta public o similar)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
</code></pre></div>
<p>viene con <strong>escuchas</strong> de tipo <strong>get</strong> (son los requires de la carpeta routes, mirarlos y veréis como son de sencillitos, más abajo los vemos)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.use('/', index);
app.use('/users', users);
</code></pre></div>
<p>Nos configura también una respuesta <strong>404</strong>, es decir, página no encontrada si recibe un <strong>path url</strong> que no existe y se lo pasa a la ultima parte que es el <strong>error handler</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
</code></pre></div>
<p>Como véis una configuración bastante sencilla por parte del fichero <strong>app.js</strong>, continuemos con nuestro <strong>bin/www</strong>.<br>
Lo siguiente <strong>requiere</strong> el módulo de <strong>debug</strong> y de <strong>http</strong> con la intención de configurar el puerto de escucha de la aplicación(con la posibilidad de usar una variable de entorno con nombre <strong>PORT</strong> para usar otra que no sea el de por defecto) y por último lo inicia.</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
</code></pre></div>
<p>Tenemos alguna cosa más pero creo que eso es lo más importante, el resto del fichero supongo que se entiende (más o menos).<br>
Veamos ahora lo que tenemos en <strong>routes</strong>, miremos por ejemplo <strong>index.js</strong></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
</code></pre></div>
<p>Tiene instanciado la propiedad <strong>router</strong>, a la que le configura un manejador en la <strong>url raíz</strong> que lo que que hará como respuesta(el parámetro <strong>res</strong> del callback) es rendear la vista index pasándole el título <strong>Express</strong>.<br>
Veamos la vista <strong>index.jade</strong> (si lo habéis dejado por defecto será jade si no aparecerá otra cosa)</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">extends layout
block content
h1= title
p Welcome to #{title}
</code></pre></div>
<p>Estp es una plantilla de <strong>jade</strong> que esta extendiendo de otra que es <strong>layout,jade</strong> pero a nosotros realmente nos interesa el <strong>title</strong>, este title es el parámetro que le enviamos desde el <strong>index.js</strong>, vamos a cambiarlo y al final veremos como queda, en el <strong>index.js</strong> ponemos esto por ejemplo (podéis poner lo que queráis)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Ninja Project' });
});
module.exports = router;
</code></pre></div>
<p>Como véis es bastante sencillo lo que nos ha configurado express, ahora mismo ya podemos arrancar la aplicación con el <strong>script</strong> que hemos visto que tenia el <strong>package.json</strong>, es decir, con <strong>npm start</strong> y ya tendríamos nuestra app con express levantada, en el puerto <strong>3000</strong>(si no hemos usado la variable de entorno para cambiarlo claro está).<br>
Una vez ejecutada si accedemos con un navegador a <strong>localhost:3000</strong> veríamos en el navegador algo similar a esto<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-18-at-21.17.00.png" alt="Don't stop the party: Node JS(VIII) Express generator"><br>
Y en la consola, veríamos lo que ya vimos usando el módulo <strong>morgan</strong><br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-18-at-20.45.15.png" alt="Don't stop the party: Node JS(VIII) Express generator"><br>
Por último comentar que aunque en el código lo llamen <em>variables de entorno</em> se pueden elegir los parámetros directamente con comandos, veamos uno que cambia todo</br></img></br></br></img></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">DEBUG=nombreApp:* PORT=3500 NODE_ENV=production npm start
</code></pre></div>
<p>Os cuento paso a paso:</p>
<ul>
<li><strong>DEBUG=nombreApp:*</strong> Esto solo es para sacar más información en los logs, si ponemos nombreApp:* nos sacaría información de debug de todos los módulos pero podríamos indicarle un módulo específico para sacar solo información de el.</li>
<li><strong>PORT=3500:</strong> Como os podéis imaginar esto nos cambiar el puerto de ejecución del 3000 que viene por defecto, al que nosotros le pongamos.</li>
<li><strong>NODE_ENV=production:</strong> Por defecto node se ejecuta en <strong>modo desarrollo</strong>, básicamente provee de información más específica en los logs, ponerlo en producción simplemente es por evitar que en los logs aparezca información sensible en cuanto a datos o diseño de nuestra infraestructura u organización.</li>
</ul>
<p>Para evitar tener que poner siempre parámetros largos recordar que podemos crear nuestros propios <strong>scripts</strong> por lo que podríamos crearnos otro que sea</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">"scripts": {
"production": "DEBUG=nombreApp:* PORT=3500 NODE_ENV=production node ./bin/www"
},
</code></pre></div>
<p>Y voilá ya tendríamos nuestro script de npm en producción, con debug y con un puerto custom.<br>
Creo que para un post tenemos suficiente jejejeje, en el siguiente vamos a ver un poco más sobre las <strong>rutas</strong>, que podemos hacer con ellas, que significado implícito tiene cada tipo....y algunas cosas más ;)</br></p>
<p>Un abrazooooorrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(VII) MVC y Express]]></title><description><![CDATA[En este post hablaremos brevemente de arquitectura de diseño y empezaremos con
el framework web express a partir del cual haremos todo el trabajo con Node como
será el crear una API.
MVC
En el mundo de la programación existen varios patrones de arquitectura de
desarrollo de software (tengo pendiente una línea de post donde hablaremos de
varios de ellos), uno de los más usados es el Modelo-Vista-Controlador (MVC), y
por el momento es como iremos viendo lo que hacemos en Node, aunque puede que no]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-vi-modulos-2/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f32</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 26 Sep 2017 08:36:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-3.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-3.jpg" alt="Don't stop the party: Node JS(VII) MVC y Express"/><p>En este post hablaremos brevemente de arquitectura de diseño y empezaremos con el framework web express a partir del cual haremos todo el trabajo con Node como será el crear una API.</p>
<h3 id="mvc">MVC</h3>
<p>En el mundo de la programación existen varios patrones de arquitectura de desarrollo de software (tengo pendiente una línea de post donde hablaremos de varios de ellos), uno de los más usados es el <strong>Modelo-Vista-Controlador</strong> (MVC), y por el momento es como iremos viendo lo que hacemos en Node, aunque puede que no lo sigamos al pie de la letra pero voy a explicar un poco los conceptos para que podáis decidir como estructurar vuestra aplicación, lo primero vamos a ver es que sería cada elemento</p>
<p><img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.22.55.png" alt="Don't stop the party: Node JS(VII) MVC y Express"/></p>
<ul>
<li><strong>Vista:</strong> la vista en una API con Node podría ser el JSON que devolvemos con los datos. O si no como su nombre indica sería el que gestiona la vista. Recibe las acciones del usuario y actúa en consecuencia comunicandose con el controlador.</li>
<li><strong>Controlador:</strong> Son los que deciden el qué, es decir son los que estan en medio de la vista y el modelo, y deciden qué es lo que mostrará (o enviará) la vista o deciden que es lo qué guardamos en el modelo.</li>
<li><strong>Modelo:</strong> Los modelos son los que gestionan la información, es decir, son los que guardan o recuperan la información desde o para los controladores según las necesidades de la vista.</li>
</ul>
<p>Nunca debe haber comunicación entre <strong>Vista y Modelo</strong></p>
<h3 id="express">Express</h3>
<p>Express es el framework web básico (muchos extienden de él) para Node y lo más fácil es darle al código para verlo, comentar que se usa más normalmente para crear APIs, que para hacer webs.<br>
Primero nos vamos a crear una carpeta llamada <strong>express_example</strong>, situamos el foco de nuestra línea de comandos dentro y ejecutamos <strong>npm init</strong> para crear nuestro fichero <strong>package.json</strong> como hemos visto en post anteriores, de momento dejamos todo por defecto (si queréis cambiar el nombre o ponerle alguna descripción eso da igual).<br>
A continuación usamos <strong>npm</strong> para instalar las dependencias necesarias de <strong>express</strong></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install express --save
</code></pre></div>
<p>Una vez ya tenemos los módulos necesarios instalados, lo siguiente sera crearnos un fichero js para empezar, lo ideal será que se llame igual que lo que hayamos puesto en el package.json, en mi caso lo he dejado por defecto por lo que lo llamare <strong>index.js</strong>. Este fichero será desde el cual se iniciará la aplicación.</p>
<p>Dentro de este fichero lo primero de todo será importar (requerir) <strong>express</strong> y ejecutarlo directamente para tener una instancia de express en nuestra app</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var app = require('express')();
</code></pre></div>
<p>yo he puesto que se ejecute directamente el método que nos devuelve el <strong>require</strong>, eso sería lo mismo que</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var express = require('express');
var app = express();
</code></pre></div>
<p>Bien a continuación yo os recomiendo que hagáis un <strong>console.log</strong> de <strong>app</strong> para haceros una idea de lo que contiene, esta práctica yo la recomiendo y la hago habitualmente para tener una mejor idea de con que elementos estoy tratando y que posibilidades tiene.</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var app = require('express')();
console.log(app);
</code></pre></div>
<p>Si ejecutamos <strong>node index.js</strong> veremos que tenemos una instancia con un montón de métodos y propiedades<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-13.51.10.png" alt="Don't stop the party: Node JS(VII) MVC y Express"><br>
Recomiendo que le echéis un vistazo aunque sea por encima ya que siempre podéis encontrar algún método que no sabéis y que os pueda ser útil en algún momento.</br></img></br></p>
<p>Una vez visto lo que contiene vamos a crear nuestro primer método de API, en este caso será una respuesta a una petición http de tipo <strong>get</strong>, para el que no sepa de lo que estoy hablando buscar en internet <strong>Métodos HTTP</strong> y os contarán todo lo necesario sobre el tema, solo por resumir un poco toda comunicación por protocolos parecidos al <strong>http</strong> tienen una especie de verbo, método o como queráis llamarlo, que indica que tipo de petición están ejecutando, es decir, si la intención de la petición de la petición es obtener datos (seria un get) o por ejemplo los están enviando (post). En este caso vamos a crear una servicio que responda de momento a peticiones <strong>get</strong>.<br>
Lo primero lo suyo sería mirar la documentación para ver de que estamos hablando, o más bien como lo hacemos y que parámetros necesita por lo que pulsar en <a href="http://expressjs.com/es/4x/api.html#app.METHOD">Express HTTP method get</a> y mirar un poco de lo que estamos hablando, básicamente necesita el path por el que que <strong>escuchará</strong> y un callback con lo que hará si coincide la llamada con el método y el path. Para aclarar un poco el <strong>path</strong> sería todo lo que esta después de una <strong>url raiz</strong>, es decir, la url raiz de este blog es <strong><a href="/">https://jlgarcia.fulldev.ninja</a></strong> y lo que este a continuación sería lo que estará escuchando nuestro método, si ponemos <strong>/</strong> estará escuchando en la <strong>url raiz</strong> que ya hemos comentado. Al lio entonces.</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var app = require('express')();
app.get('/', function(request, response){
});
</code></pre></div>
<p>Para que quede más claro he puesto nombres muy específicos en sus parámetros</p>
<ul>
<li><strong>request</strong>: que será toda la información de la petición que recibe.</li>
<li><strong>response</strong>: Como su nombre indica será la respuesta que devolverá nuestra API.<br>
Vamos a generar una respuesta simple para probar, lo primero hacemos un console.log con lo que contiene la petición que hemos recibido, y segundo vamos a devolver un simple string, para ello ponemos lo siguiente</br></li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.get('/', function(request, response){
console.log('He recibido una petición, esta en concreto',request);
response.send('Me ha llegado tu NinjaPetición');
});
</code></pre></div>
<p>Ya tenemos nuestro método que responde a las llamadas de tipo <strong>get</strong> en la <strong>url raiz</strong> mostrandonos la información de la petición recibida y devoldiendo algo, pero esto por si solo no hace nada tenemos que indicarle a <strong>Node</strong> que se quede a la escucha en algún puerto, para hacer esto usaremos el método <strong>listen</strong> de nuestra instancia de express, al igual que antes os insto a mirar en la <a href="http://expressjs.com/es/4x/api.html#app.listen">documentación oficial de express</a>. Una vez visto lo que podemos hacer escribimos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">app.listen(2000, function(){
console.log('superapi iniciada en puerto 2000');
});
</code></pre></div>
<p>Esto nos iniciaría un proceso que esta escuchando en el puerto 2000, a la espera de recibir alguna petición get (tal cual hemos puesto arriba) y cuando arranca el proceso nos avisa con un log. Tenemos que tener siempre en cuenta que, como pone en la documentación, <strong>app.listen</strong> es igual que <strong>http.server.listen()</strong>. Esto es importante porque en la actualidad no se suele escuchar en http si no en https por lo que realmente el método en un servicio en producción sería <strong>https.server.listen()</strong>, pero esto ya lo veremos más adelante. Por ahora nuestro fichero <strong>index.js</strong> quedaría de esta manera</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var app = require('express')();
app.get('/', function(request, response){
console.log('He recibido una peticion, esta en concreto',request);
response.send('Me ha llegado tu NinjaPetición');
});
app.listen(2000, function(){
console.log('superapi iniciada en puerto 2000');
});
</code></pre></div>
<p>Ahora vamos a ejecutarlo con <strong>node index.js</strong> y si todo va bien deberíamos ver en la consola<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-19.04.03.png" alt="Don't stop the party: Node JS(VII) MVC y Express"/></br></p>
<p>Ya tenemos nuestra API en pie, para probarla escribimos en el navegador <strong>localhost:2000</strong>, no os preocupéis por el tipo de petición, por defecto el navegador siempre usa el método <strong>get</strong>. Si todo va bien deberiamos ver en el navegador algo similar a esto<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-19.08.09-1.png" alt="Don't stop the party: Node JS(VII) MVC y Express"><br>
Y en nuestra consola nos aparecezan un montón de lineas con toda la información que tiene la petición que ha recibido nuestra API desde el navegador<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-19.09.40.png" alt="Don't stop the party: Node JS(VII) MVC y Express"><br>
Como veis es un montón de información, por ejemplo en algun punto estan los <strong>headers</strong> donde podemos encontar el tipo de navegador<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-19.11.25.png" alt="Don't stop the party: Node JS(VII) MVC y Express"><br>
muy útil si queremos diferenciar lo que responde nuestra API segun el navegador, o el idioma<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-19.12.59.png" alt="Don't stop the party: Node JS(VII) MVC y Express"><br>
si por ejemplo tenemos el contenido en varios idiomas distintos.<br>
Lo que quiero decir es que si miráis un poco veréis un montón de información que puede ser muy útil según para que, y esta es usable como cualquier otro parámetro, por ejemplo vamos a confirmar el método que hemos recibido, para ello cambiamos nuestro console.log a</br></br></img></br></br></img></br></br></img></br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">console.log('He recibido una peticion, esta en concreto',request.method);
</code></pre></div>
<p>que al llamar de nuevo a <strong>localhost:2000</strong>, nos mostrará<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-19.17.03.png" alt="Don't stop the party: Node JS(VII) MVC y Express"/></br></p>
<p>Como extra, vamos a usar un módulo para que en nuestra consola aparezca información útil directamente por cada petición que recibe nuestra API (esto realmente suele usarse como un log y se almacena en un fichero para que se pueda revisar), este módulo se llama <strong>morgan</strong> (hay muchos otros). Para usarlo hacemos lo de siempre, <strong>npm install morgan --save</strong> y para usarlo por el momento quitamos el <strong>console.log</strong> y sería suficiente con <strong>importar/requerir</strong> el paquete y usarlo, ponemos debajo de nuestro anterior require</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var morgan = require('morgan');
app.use(morgan('dev'));
</code></pre></div>
<p>Ejecutamos con <strong>node index.js</strong> y al llamar de nuevo a <strong>localhost:2000</strong> en nuestro navegador nuestra consola nos mostrará<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-19.25.01.png" alt="Don't stop the party: Node JS(VII) MVC y Express"><br>
Vemos que en los datos que nos muestra aparece el método con el nos han llamado, el path, <strong>el código del estado HTTP</strong> y el tiempo de la respuesta. En el caso de que tuvieramos algún error nos aparecería el código http pertinente lo que puede ser muy útil para depurar algún tipo de error.</br></img></br></p>
<p>En este post hemos visto el uso básico de express con node, creando una API muy simplona, además hemos visto que es exactamente el MVC y por último como ver información útil de las peticiones que recibe nuestra API creo que para un post ya es suficiente jejejeje. En el próximo seguiremos viendo cosas de express y muchas cosas más.</p>
<p>Un abrazooorrrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(VI) Módulos y NPM]]></title><description><![CDATA[En este punto vamos a empezar con los módulos que son una parte muy importante y
muy útil realmente.
Que son?
Bien los módulos básicamente son código JavaScript que utilizamos como si de una
librería externa se tratase, es decir los importamos. Normalmente estos módulos
se encuentran en una carpeta llamada node_modules en nuestro proyecto, que se
crea automáticamente cuando instalamos algo con npm, por ejemplo. Pero claro no
hemos visto nada de npm todavía ¿verdad?, pues simplemente poner en la]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-vi-modulos/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f31</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 21 Sep 2017 08:03:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-2.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-2.jpg" alt="Don't stop the party: Node JS(VI) Módulos y NPM"/><p>En este punto vamos a empezar con los módulos que son una parte muy importante y muy útil realmente.</p>
<h2 id="queson">Que son?</h2>
<p>Bien los módulos básicamente son código JavaScript que utilizamos como si de una librería externa se tratase, es decir los importamos. Normalmente estos módulos se encuentran en una carpeta llamada <strong>node_modules</strong> en nuestro proyecto, que se crea automáticamente cuando instalamos algo con <strong>npm</strong>, por ejemplo. Pero claro no hemos visto nada de npm todavía ¿verdad?, pues simplemente poner en la línea de comandos (con la posición o ubicación en el path de vuestro proyecto) y poner</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install async
</code></pre></div>
<p>Async es un módulo de npm que nos ayuda con la gestión de código asíncrono(como lo hace Node recordemos el event loop ;) ). De primeras al ejecutar el comando veréis algo similar a esto<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-15-at-20.42.12.png" alt="Don't stop the party: Node JS(VI) Módulos y NPM"><br>
De momento no hagáis mucho caso a lo que pone ya entraremos en eso más adelante, lo que quería mostraros es que si miráis vuestra carpeta de proyecto os ha creado una nueva carpeta llamada <strong>node_modules</strong> y si miráis lo que hay dentro podréis ver que os ha descargado dos carpetas y estas a su vez tienen un montón de ficheros y carpetas no?....pues esto son módulos, prácticamente cada fichero <strong>js</strong> esta configurado como un módulo.</br></img></br></p>
<p>Ahora que ya hemos visto un poco como es un módulo, hablemos un poco más en detalle de ellos.<br>
Están basados en el estándar <a href="http://requirejs.org/docs/commonjs.html">CommonJS</a> y para usarlos tenemos que <strong>cargarlos</strong> en nuestros ficheros js, esto lo hacemos con la instrucción <strong>require</strong>.Esta instrucción es <strong>síncrona</strong>, es decir, no puede hacerse en un callback ni nada por el estilo.<br>
Algo bueno que tienen los módulos es que son <a href="http://www.oodesign.com/singleton-pattern.html"><strong>singletons</strong></a>, que para el que no sepa que es, es un patrón de diseño con el cual nos aseguramos que solo tenemos una instancia de un objeto, como puede ser una conexion a una base de datos. Lo que hace es que la primera vez que ejecutamos el <strong>require</strong> se ejecuta el código necesario para crear una instancia nueva de nuestro módulo, el resto de veces que llamemos a <strong>require</strong> para el mismo módulo nos devolverá la misma instancia que se habia creado previamente.<br>
Pero, y como sabe lo que tiene que devolver al hacer el <strong>require</strong>?...Si miráis cualquier módulo veréis que al final tienen siempre algo parecido a esto</br></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">module.exports = nombreAlgunaFunciónUObjeto;
</code></pre></div>
<p>Eso es lo que realmente se importa, lo que está indicado en esa línea. Y para importar lo que haríamos sería</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var nombre = require ('nombreAlgunaFunciónUObjeto');
</code></pre></div>
<p>Con lo que quedaría almacenado en esa variable lo que se había exportado. Lo que contenga el <strong>require</strong> depende un poco de donde se encuentre el fichero o el script del cual queremos importar y de donde esté nuestra aplicación de Node. Como tal tenemos varias opciones</p>
<ul>
<li>Que esté en la carpeta <strong>node_modules</strong> local, es decir, la que nos ha creado en nuestro proyecto cuando hemos usado <strong>npm install</strong></li>
<li>Puede encontrarse también en la carpeta <strong>node_modules</strong> global, ésta la crea npm al instalar node, y nosotros podemos almacenar módulos en ella usando <strong>npm install -g nombreMódulo</strong></li>
<li>Si lo que ponemos empieza por './', '../' o similar lo buscará en la ruta que indiquemos partiendo de la nuestra (la del fichero donde usamos el require)</li>
<li>Si es un módulo del propio core de node con poner el nombre seria suficiente</li>
</ul>
<p>Si tenemos que usar la ruta específica puede que tengamos que poner una ruta larguisima, esto se puede evitar de varias formas usando la variable de entorno <strong>NODE PATH</strong> o a partir de la versión 2.0 de npm podríamos ponerlo en el fichero <strong>packaje.json</strong> (ya hablaremos de él). Si tenéis curiosidad sobre como serían estas formas navegar por el ciber-espacio que ya hay mucha literatura sobre esto.</p>
<p>Antes de terminar este post hagamos un ejemplo creando nuestro propio módulo.<br>
Vamos a usar la carpeta <strong>node_modules</strong> que ya tenemos, y lo que hacemos es crear dentro un fichero js nuevo con nombre <strong>heroName.js</strong> y ponemos este código</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var heroName = function(name){
console.log("Nuestro héroe es ",name);
}
module.exports = heroName;
</code></pre></div>
<p>Y ahora fuera de la carpeta node_modules en nuestro proyecto creamos otro fichero js que yo lo he llamado <strong>modules.js</strong> y es tan simple como poner</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var heroName = require('heroName');
heroName("Dr.Manhattan")
</code></pre></div>
<p>Y listo, como véis es algo bastante simple y funciona<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-15-at-21.57.14.png" alt="Don't stop the party: Node JS(VI) Módulos y NPM"/></br></p>
<p>Tambiés es posible exportar más de un método u objeto, para ello cambiemos un poco el código de nuestro módulo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var heroName = function(name){
console.log("Nuestro héroe es ",name);
}
var powerLevel = function(power){
console.log("Power level es:",power);
}
module.exports = {
heroName: heroName,
powerLevel: powerLevel
}
</code></pre></div>
<p>Y para usarlo, ahora nuestro require realmente devuelve un objeto con 2 métodos en él por lo que para usarlos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var hero = require('heroName');
console.log(hero);
hero.heroName("Dr.Manhattan");
hero.powerLevel("9000");
</code></pre></div>
<p>He añadido un log de nuesto objeto <strong>hero</strong> para que veáis lo que contiene<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-15-at-22.05.12.png" alt="Don't stop the party: Node JS(VI) Módulos y NPM"/></br></p>
<p>Si os fijáis ahora <strong>hero</strong> es un objeto con dos propiedades que realmente son dos funciones, las cuales podemos usar tranquilamente como si de cualquier otro método se tratara.</p>
<h3 id="npm">NPM</h3>
<p>Son las siglas de <strong>Node Package Manager</strong>,y lo que nos permite es gestionar las dependencias de nuestra aplicación o proyecto, las instala, elimina o actualiza. Y también nos permite instalarlas de manera global para que podamos usarlas en cualquier proyecto.<br>
<strong>NPM</strong> se apoya en un fichero llamado <strong>package.json</strong> que nos ayuda a mantener información de las dependencias de nuestro proyecto y las versiones que usamos.</br></p>
<p>Si comenzamos con un proyecto nuevo lo primero que deberiamos hacer es ejecutar</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm init
</code></pre></div>
<p>Esto lo que haría sería crearnos un fichero <strong>package.json</strong> preguntandonos ciertas cosas sobre nuestro proyecto para luego almacenarlas en ese fichero<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.42.23.png" alt="Don't stop the party: Node JS(VI) Módulos y NPM"/></br></p>
<p>Tenemps algunas cosas útiles como por ejemplo la parte de <strong>scripts</strong> que vemos en el fichero. Lo que pongamos en esos scripts actuará como alias de algún comando que queramos ejecutar, por ejemplo podemos poner:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> "scripts": {
"test": "node test.js",
"start": "node callbacks.js"
},
</code></pre></div>
<p>Con esto solo tendríamos que poner <strong>npm</strong> seguido de nuestro nombre de script para ejecutarlo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm start
</code></pre></div>
<p><img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.52.34.png" alt="Don't stop the party: Node JS(VI) Módulos y NPM"><br>
Como vemos se ejecuta el fichero que ya creamos en algún post anterior. Puede que este caso no tenga mucha utilidad, pero si en lugar de ese comando tan simple tuvieramos que añadirle parámetros o queremos llamar a más elementos en la misma ejecución puede ser muy útil.</br></img></p>
<p>Para gestionar las dependencias de Node y que se guarden en nuestro <strong>package.json</strong> solo tenemos que ejecutar el comando de instalación de npm seguido de <strong>--save</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install json --save
</code></pre></div>
<p>Ahora nuestro fichero package.json tendría esta pinta<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-12.56.54.png" alt="Don't stop the party: Node JS(VI) Módulos y NPM"/></br></p>
<p>Vemos que nos ha añadido la <strong>dependencia json con su número de versión</strong>.</p>
<p>También hemos comentado que podemos instalar dependencias de manera global en nuestro equipo, para ello con que ejecutemos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install -g jslint
</code></pre></div>
<p>Esto nos instalará en <strong>/usr/local/lib/node_modules/</strong> la dependencia y creará un acceso directo o enlace simbólico en <strong>/usr/local/bin</strong> para que podamos ejecutarla desde cualquier sitio si es necesario.<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-16-at-13.01.32.png" alt="Don't stop the party: Node JS(VI) Módulos y NPM"/></br></p>
<p>Por último un detalle en cuanto las versiones de las dependencias, si os fijáis antes del número de versión pone un <strong>^</strong> y ¿por qué?....pues significa que npm puede actualizar esa dependencia siempre y cuando la versión no modifique el valor más a la izquierda que sea distinto de cero, es decir, si tenemos la versión</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">^9.0.6
</code></pre></div>
<p>El <strong>9</strong> no podría modificarlo, eso significa que la versión en este caso puede pasar de 9.0.7 a 9.X.X, pero si la versión que tenemos es</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">^0.2.5
</code></pre></div>
<p>Entonces la versión solo puede estar entre 0.2.5 a 0.2.X siendo X mayor que 5.</p>
<p>En el próximo post empezaremos ya con express y el trabaj o propio de node.</p>
<p>Un abrazooorrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(V) Basics]]></title><description><![CDATA[Tras nuestro repaso de algunas características que nos serían útiles de
JavaScript, vamos a ver algunas propiedades, métodos o lógicas de NodeJS que nos
ayudarán con el desarrollo de servicios en este lenguaje.
Event Loop
Node usa un solo hilo, o más bien como concepto de ciclo de vida para nosotros
es así, es posible que internamente se ejecute de otra forma pero insisto no
para nosotros.
Este hilo funciona como un bucle, es decir, lo que hace en cada vuelta es
ejecutar el código que le toca e]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-v/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f2e</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 18 Sep 2017 08:35:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner-1.jpg" alt="Don't stop the party: Node JS(V) Basics"/><p>Tras nuestro repaso de algunas características que nos serían útiles de JavaScript, vamos a ver algunas propiedades, métodos o lógicas de <strong>NodeJS</strong> que nos ayudarán con el desarrollo de servicios en este lenguaje.</p>
<h3 id="eventloop">Event Loop</h3>
<p>Node usa un solo hilo, o más bien como concepto de ciclo de vida para nosotros es así, es posible que internamente se ejecute de otra forma pero insisto no para nosotros.<br>
Este hilo funciona como un bucle, es decir, lo que hace en cada vuelta es ejecutar el código que le toca en ese momento(todo síncrono), y si se encuentra algún callback lo ejecuta <strong>pero</strong>, repito <strong>pero</strong> los va dejando pendientes y comprueba si han terminado en vueltas posteriores y si han terminado entonces ejecúta sus el código pertinente a ese callback.<br>
Por este motivo todo el nuestro código en <strong>NodeJS</strong> tenemos que procurar que sea no bloqueante, si puede bloquear de algúna forma el hilo eso significa que tenemos que hacerlo asíncrono para que el event loop(nuestro único hilo) no se detenga. Todas las llamadas a funciones de entrada/salida lectura/escritura del disco, red, base de datos deberia ser asíncrono.</br></br></p>
<h3 id="process">Process</h3>
<p>Process es un objeto global que está disponible en nuestras aplicaciones, el cual nos va a permitir por ejemplo:<br>
saber en que sistema operativo está funcionando,</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">process.platform;
</code></pre></div>
<p>parar la ejecución con un código de salida,</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">process.exit(int); //0 para salida correcta
</code></pre></div>
<p>responder a eventos como este de <strong>'exit'</strong> con un callback para hacer algo antes de parar la ejecución</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">process.on('exit',callback);
</code></pre></div>
<p>o hacer algo en la siguiente vuelta del <strong>event loop</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">process.nextTick(function(){
console.log('Siguiente vueltaaaaaaaaaa')
}
</code></pre></div>
<p>Ejemplo de información de sistema</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var systemInfo = {
pid: process.pid,
version: process.version,
platform: process.platform,
title: process.title,
arg: process.argv,
execPath: process.execPath,
folder: process.cwd()
};
console.log('Id de proceso ' + systemInfo.pid)
console.log('Versión de Node' + systemInfo.version)
console.log('Plataforma ' + systemInfo.platform)
console.log('Nombre de proceso ' + systemInfo.title)
console.log('Argumentos que recibe ' + systemInfo.arg)
console.log('Path de ejecución de proceso '+ systemInfo.execPath)
console.log('Path de ejecución de aplicación de node '+ systemInfo.folder)
</code></pre></div>
<p>Con este código vereis varios ejemplos de información que podemos sacar gracias a process.</p>
<p>Veamos ahora un ejemplo de <strong>exit</strong>, para ello vamos poner antes de todos los logs lo siguiente</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">process.exit(2);
</code></pre></div>
<p>Si ahora ejecutais vereis como se finaliza el programa antes de mostrar nada y podéis comprobar el código de salida con<br>
En linux/Mac:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">echo $?
</code></pre></div>
<p>En Windows:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">echo %errorlevel%
</code></pre></div>
<p><img srcset="/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.46.31.png" alt="Don't stop the party: Node JS(V) Basics"/></p>
<p>Por último vamos a probar a realizar algo justo antes de salir para ello, vamos a dejar nuestro código asi:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var systemInfo = {
pid: process.pid,
version: process.version,
platform: process.platform,
title: process.title,
arg: process.argv,
execPath: process.execPath,
folder: process.cwd()
};
process.on('exit', () => { console.log('Antes de salir digo BYEEEEEe')})
console.log('Id de proceso ' + systemInfo.pid)
console.log('Versión de Node' + systemInfo.version)
console.log('Plataforma ' + systemInfo.platform)
process.exit(0);
console.log('Nombre de proceso ' + systemInfo.title)
console.log('Argumentos que recibe ' + systemInfo.arg)
console.log('Path de ejecución de proceso '+ systemInfo.execPath)
console.log('Path de ejecución de aplicación de node '+ systemInfo.folder)
</code></pre></div>
<p>Si ahora ejecutamos esto veréis algo similar a esto<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.51.57.png" alt="Don't stop the party: Node JS(V) Basics"><br>
Como veis nos muestra los tres primeros logs y en cuanto llega al exit se despide y ya no nos muestra más, sencillo verdad?</br></img></br></p>
<h3 id="eventemitter">EventEmitter</h3>
<p>Este método puede ser una herramienta muy útil para según que cosa, lo que nos permite es asignar una o varias funciones a un evento, es decir, cada vez que llamemos a ese evento se ejecutará su función asignada.<br>
Veamoslo con un ejemplo, antes de nada vamos a importar lo que necesitamos para usarlo:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">'use strict';
var events = require('events');
var eventEmitter = new events.EventEmitter();
</code></pre></div>
<p>Ya estamos listos, ahora pensemos en cualquier juego de <strong>Mario Bros.</strong>. Cada vez que nuestro Mario hacia algún tipo de evento distinto a moverse izquierda o derecha emitía un sonido, ya fuera saltar, coger alguna moneda o saltar sobre alguna inocente tortuga, es decir, a nivel de código tiene que tener un método similar a <strong>playSound</strong> no? Pues vamos a crearlo</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function playSound(){
console.log("Mario hace algo");
}
</code></pre></div>
<p>Ya tenemos nuestro método, ahora como hemos comentado esto tiene que responder a algún evento, por lo que vamos a asignarle un nombre de evento a ese método</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">eventEmitter.on('play music',playSound);
</code></pre></div>
<p>Para llamar a ese evento que hemos creado es tan simple como <strong>emitirlo</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">eventEmitter.emit('play music');
</code></pre></div>
<p>Asi de simple jejejejeje pero esto realmente si lo pensamos es poco eficiente, con este tendriamos que crear realmente un evento por cada tipo desonido, no?......Pues no realmente, también nos permite pasarle parámetros, vamos a cambiar nuestro método para que reciba un parámetro donde indicariamos el tipo de sonido</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function playSound(action){
console.log("Mario ",action);
}
</code></pre></div>
<p>Y hagamos que nuestro <strong>emit</strong> le pase algún parámetro</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">eventEmitter.emit('play music','coge moneda');
</code></pre></div>
<p>Y voilá si ejecutámos veremos que <strong>Mario ha cogido una moneda</strong><br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-15-at-09.04.01.png" alt="Don't stop the party: Node JS(V) Basics"><br>
Comentar que podemos suscribir varias funciones al mismo evento, simplemente tendriamos que hacer otro <strong>eventEmitter.on</strong> con el mismo nombre de evento y otro nombre de función, esto lo que haría seria ejecutar ambos.<br>
Y es en este punto donde por ejemplo podemos ver mejor su utilidad, si seguimos usando nuestro ejemplo de Mario, supongamos el momento en el que Mario salta sobre una tortuga, esto tendría que gestionar entre otras cosas el sonido al pisar la tortuga, el efecto visual de la tortuga y si esto nos da puntos tendríamos que efectuar la gestión de estos. Son bastantes cosas no?....pero si tenemos todas estas necesidades subscritas al mismo evento, por ejemplo <strong>turtleDeath</strong> solo tendriamos que hacer</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">eventEmitter.emit('turtleDeath')
</code></pre></div>
<p>Y listo se ejecutarian todos los eventos y el código quedaría bastante limpio.</p>
<p>Creo que más o menos queda todo claro, en el próximo post hablaremos de los <strong>módulos</strong> de Node y de como crearlos.</p>
<p>Un abrazooorrrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[React Superhero (V): Mobx]]></title><description><![CDATA[En este post hablaremos de una librería muy útil llamada Mobx que entre otras
cosas nos facilita un poco el desarrollo en cuanto a la comunicación entre
componentes se refiere, es decir, ya hemos visto un poco como comunicarnos de un
componente a otro para realizar alguna modificación en alguna propiedad, pues
bien Mobx nos facilita este planteamiento (entre otras cosas claro ;) ). Si
queréis algo más de información aqui tenéis la página oficial de Mobx
[https://mobx.js.org/]
Instalación
Para i]]></description><link>https://jlgarcia.fulldev.ninja/react-superhero-v-mobx/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f2a</guid><category><![CDATA[reactjs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 12 Sep 2017 08:09:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom-1.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom-1.jpg" alt="React Superhero (V): Mobx"/><p>En este post hablaremos de una librería muy útil llamada <strong>Mobx</strong> que entre otras cosas nos facilita un poco el desarrollo en cuanto a la comunicación entre componentes se refiere, es decir, ya hemos visto un poco como comunicarnos de un componente a otro para realizar alguna modificación en alguna propiedad, pues bien <strong>Mobx</strong> nos facilita este planteamiento (entre otras cosas claro ;) ). Si queréis algo más de información aqui tenéis la página oficial de <a href="https://mobx.js.org/">Mobx</a></p>
<h3 id="instalacin">Instalación</h3>
<p>Para instalar <strong>mobx</strong> usaremos nuestro magnífico <strong>npm</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm install mobx mobx-react --save
</code></pre></div>
<p>Esto nos instalará en el proyecto los módulos de NodeJS necesarios para poder trabajar con <strong>Mobx</strong></p>
<h3 id="usandomobx">Usando Mobx</h3>
<p>Bien vamos a empezar a partir de la estructura de proyecto que teniamos en el post anterior (tras ejecutar nuestro create-app....).<br>
Vamos a trabajar sobre el fichero <strong>App.js</strong> que es el componente que se esta rendeando por defecto, pero vamos a cambiarlo un poco y asi vemos que realmente estamos en este punto, vamos a cambiar la frase que aparece debajo de <strong>Welcome to React</strong> para indicar que trabajaremos despues de esa linea:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
We started working below this line
</p>
</div>
);
}
}
export default App;
</code></pre></div>
<p>Tras guardar, automáticamente tendriamos algo similar a<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-09-at-13.37.40.png" alt="React Superhero (V): Mobx"><br>
Bien ya sabemos donde estamos, ahora haremos un ejemplo simple para ver que es lo que conseguimos con <strong>Mobx</strong>, vamos a mostrar un número y este aumentará cuando pulsemos un botón.<br>
Primero mostremos nuestro número, en un principio es algo sencillo que ya hemos visto no?, creamos un componente nuevo y lo indicamos en el componente que se esta renderizando como principal no??...... si esa es una opción pero al final estaríamos haciendo lo mismo que ya hemos visto y entonces para que queremos <strong>mobx</strong> no??. Pues bien la teoría del componente es válida a medias, vamos a crear una clase y en esta tenemos que importar <strong>extendObservable</strong> de la librería de <strong>mobx</strong>. Yo le he puesto el nombre <strong>FirstMobxClass.js</strong> y esto es lo que ponemos</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import {extendObservable} from 'mobx'
class FirstMobxClass {
constructor(){
//Recibe el objeto a observar y las propiedades
extendObservable(this,{
number: 1
})
}
}
//Creamos una nueva instancia de nuestra clase,la almacenamos
// y la exportamos para que se tenga acceso desde fuera
//de esta clase
var numberMobxClass = new FirstMobxClass();
export default numberMobxClass;
</code></pre></div>
<p>Con esto tendríamos una variable con una propiedad number que deberíamos poder usar. Para ello volvamos a nuestra clase App.js y ponemos lo siguiente:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//Our imports
import numberMobxClass from './FirstMobxClass';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
We started working below this line
</p>
<h2>{ numberMobxClass.number }</h2>
</div>
);
}
}
export default App;
</code></pre></div>
<p>Para diferenciar los imports que ya teniamos de los nuevos he indicado el comentario <strong>our imports</strong>. Como véis lo que importamos es nuestra variable del fichero con nombre <strong>FirstMobxClass</strong> y para usarlo nos valemos de las magias del lenguaje <strong>JSX</strong> y con poner</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><h2>{ numberMobxClass.number }</h2>
</code></pre></div>
<p>Ya tendríamos nuestra linea con el número que hemos puesto<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.01.56.png" alt="React Superhero (V): Mobx"/></br></p>
<p>Lo siguiente será crear nuestro botón, en este caso seguimos la teoría inicial de los componentes que ya sabíamos, me refiero a que lo creamos como un componente normal. Creamos el fichero <strong>IncreaseNumber.js</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import React, { Component } from 'react';
class IncreaseNumber extends Component {
render(){
return(
<button>Increase Number</button>
)
}
}
export default IncreaseNumber;
</code></pre></div>
<p>De momento nada nuevo, para verlo lo importamos en <strong>App.js</strong> y lo ponemos a continuación, es decir ahora en App.js debajo de <strong>Our imports</strong> añadimos un import más debajo del <strong>numberMobxClass</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Our imports
import numberMobxClass from './FirstMobxClass';
import IncreaseNumber from './IncreaseNumber';
</code></pre></div>
<p>Y luego debajo de nuestro número le ponemos el botón</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><h2>{ numberMobxClass.number }</h2>
<IncreaseNumber/>
</code></pre></div>
<p>Y al guardar ya veríamos nuestro botón<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.12.23.png" alt="React Superhero (V): Mobx"><br>
Pero aunque pulsemos de momento no hace nada no??....continuemos ahora para añadirle funcionalidad. Al igual que haciamos antes necesitamos un método que haga que aumente nuestro número, y al igual que haciamos antes lo mejor es que lo creemos en el mismo punto que donde tenemos nuestra propiedad. Esto es tan simple como sumarle 1 al número, es decir añadimos a nuestra clase <strong>FirstMobxClass</strong> el método <strong>increase</strong></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class FirstMobxClass {
constructor(){
//Recibe el objeto a observar y las propiedades
extendObservable(this,{
number: 1
});
}
increase(){
this.number = this.number + 1;
}
}
</code></pre></div>
<p>Ya tenemos nuestro método ahora indiquemosle a nuestro botón que tiene que usarlo, probemos a ponerlo directamente con un <strong>onClick</strong> en el componente <strong>IncreaseNumber</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import React, { Component } from 'react';
import numberMobxClass from './FirstMobxClass';
class IncreaseNumber extends Component {
render(){
return(
<button onClick={numberMobxClass.increase} >Increase Number</button>
)
}
}
export default IncreaseNumber;
</code></pre></div>
<p>Si os fijáis hemos importado nuestra clase <strong>numberMobxClass</strong> y hemos usado nuestro método <strong>increase</strong> directamente en el <strong>onClick</strong>, bien si guardamos vemos que la página renderiza bien pero que pasa si pulsamos.......UPSSS!!!<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.33.03.png" alt="React Superhero (V): Mobx"><br>
Vemos que nos sale este error, y eso es como os podéis imaginar que <strong>this</strong> no tiene nada, diréis "pues entonces podemos ponerle un <strong>bind</strong> igual que haciamos antes y ya esta", bueno pues vamos a probarlo a ver que pasa y de paso le ponemos al método <strong>increase</strong> un log para ver que tiene <strong>this</strong>.<br>
El método <strong>increase</strong> ahora quedaria así</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">increase(){
console.log(this);
this.number = this.number + 1;
}
</code></pre></div>
<p>Y nuestro <strong>onClick</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><button onClick={numberMobxClass.increase.bind(this)} >Increase Number</button>
</code></pre></div>
<p>Veamos que pasa cuando pulsamos<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.37.48.png" alt="React Superhero (V): Mobx"><br>
No nos da error pero si nos fijamos en lo que nos devuelve nuestro log, la propiedad <strong>number</strong> es <strong>NaN</strong> y eso ¿por qué? Pues porque realmente estamos pasando con <strong>bind</strong> el <strong>this</strong> de nuestro componente <strong>IncreaseNumber</strong> el cual no tiene esa propiedad, hagamos un pequeño ejemplo para verlo, creemos una propiedad en el componente <strong>IncreaseNumber</strong> como hemos visto en anteriores post y veamos el log ahora.<br>
El componente <strong>IncreaseNumber</strong> quedaria asi</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class IncreaseNumber extends Component {
constructor(){
super();
this.test = 2;
}
render(){
return(
<button onClick={numberMobxClass.increase.bind(this)} >Increase Number</button>
)
}
}
</code></pre></div>
<p>Y al pulsar tenemos este log<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.47.11.png" alt="React Superhero (V): Mobx"><br>
Si os fijáis <strong>number</strong> sigue siendo <strong>NaN</strong> pero sin embargo tenemos nuestra propiedad <strong>test</strong> con el valor que hemos puesto, entonces quiere decir que estamos pasando el <strong>contexto</strong> del componente <strong>IncreaseNumber</strong>.... y entonces como lo hacemos??...Es más fácil de lo que parece, <strong>onClick</strong> espera una función no?, pues simplemente usemos una función que cada vez que se use esta "llame" a nuestro método <strong>increase</strong> (al estilo típico de la programación habitual)<br>
Con esta teoría nuestro <strong>onClick</strong> quedaría así</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><button onClick={() => numberMobxClass.increase()} >Increase Number</button>
</code></pre></div>
<p>Veamos lo que tiene <strong>this</strong> ahora<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-09-at-14.52.52.png" alt="React Superhero (V): Mobx"><br>
Anda!! Ahora nuestro <strong>number</strong> si aumenta pero..... en nuestra página no se ve.....y eso?? bueno la explicación es sencilla no estamos <strong>"observando"</strong> la propiedad para que responda los cambios y como hacemos eso?...Fácil, importamos <strong>observer</strong> de la libreria <strong>mobx-react</strong> y le indicamos que observe donde estamos renderizando, es decir en <strong>App.js</strong>, por lo que el componente quedaría asi</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//Our imports
import numberMobxClass from './FirstMobxClass';
import IncreaseNumber from './IncreaseNumber';
import { observer } from 'mobx-react';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
We started working below this line
</p>
<h2>{ numberMobxClass.number }</h2>
<IncreaseNumber/>
</div>
);
}
}
export default observer(App);
</code></pre></div>
<p>Y voilá ya tenemos nuestro numero aumentando en nuestra página<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-09-at-15.00.31.png" alt="React Superhero (V): Mobx"/></br></p>
<p>Espero que quede más o menos claro como estamos usando la característica <strong>observable</strong> que nos proporciona <strong>Mobx</strong>, que realmente nos facilita un poco estar pendiente de los estados o cambios de nuestras propiedades.</p>
<p>En el siguiente post seguiremos viendo que más cosas podemos hacer con <strong>Mobx</strong>, nos vemos, un abrazooorrrrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(IV) Hablemos un poco de JS (III)]]></title><description><![CDATA[Herencia
En JavaScript también existe este concepto, con la ayuda de lo que hemos visto
en el post anterior, los prototypes, para resumir un poco lo que hacemos es
llamar al "padre" del cual queramos heredar(como si llamaramos a super en otros
lenguajes) y le decimos que cambie su this(su contexto o instancia) por el
nuestro junto con los parámetros que necesitemos.
Creo que en este caso es mejor verlo con un ejemplo, para ello vamos a crearnos
un constructor y luego extenderemos de él.
functio]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-iv-hablemos-un-poco-de-js-iii/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f2d</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 12 Sep 2017 07:06:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="herencia">Herencia</h2>
<img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" alt="Don't stop the party: Node JS(IV) Hablemos un poco de JS (III)"/><p>En JavaScript también existe este concepto, con la ayuda de lo que hemos visto en el post anterior, <strong>los prototypes</strong>, para resumir un poco lo que hacemos es llamar al <strong>"padre"</strong> del cual queramos heredar(como si llamaramos a super en otros lenguajes) y le decimos que cambie su <strong>this</strong>(su contexto o instancia) por el nuestro junto con los parámetros que necesitemos.<br>
Creo que en este caso es mejor verlo con un ejemplo, para ello vamos a crearnos un constructor y luego extenderemos de él.</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function Superhero(alias) {
this.alias = alias;
this.getInfo = function () {
console.log('Nuestro héroe se llama ' + this.alias);
}
}
</code></pre></div>
<p>Este sería nuestro constructor, vamos a crear un elemento para ver que funciona</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var mr_manhattan = new Superhero('Dr. Manhattan');
mr_manhattan.getInfo();
</code></pre></div>
<p>Si ejecutamos esto(recordar con <strong>node nombreFicheroJS</strong>), veríamos que funciona<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-12-at-21.43.50.png" alt="Don't stop the party: Node JS(IV) Hablemos un poco de JS (III)"/></br></p>
<p>Ahora vamos a crear otra función que herede de la primera, para ello nos valemos del método que tienen todas las funciones <strong>call</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function Hero(alias){
Superhero.call(this, alias);
}
</code></pre></div>
<p>Como véis le pasamos el this de nuestro método y le pasamos el parámetro de la función superhero.<br>
Por último añadimos a los prototipos de la función Hero, un nuevo <strong>Superhero</strong> para que realmente lo herede, y tras esto ya podriamos usar <strong>Hero</strong> con las propiedades de <strong>Superhero</strong></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">Hero.prototype = new Superhero('Walter Joseph Kovacs');
var rorschach = new Hero('Rorschach');
rorschach.getInfo();
console.log(Object.getPrototypeOf(rorschach))
console.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))
console.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))
</code></pre></div>
<p>Nuestro <strong>rorschach</strong> puede usar los mismos métodos que <strong>Superhero</strong>, y para comprobarlo he vuesto unos cuantos logs que nos mostrarían cuales son los prototypes que tiene, y si es una instancia de cada uno de nuestros constructores<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-13-at-08.42.43.png" alt="Don't stop the party: Node JS(IV) Hablemos un poco de JS (III)"/></br></p>
<h2 id="herenciamltiple">Herencia Múltiple</h2>
<p>Podemos simular herencia múltiple aprovechando lo que acabamos de hacer y usando el método <strong>assign</strong>, este método lo que hace es copiar las propiedades de un objeto en otro, con lo que el objeto destino puede usarlas como si fueran suyas. Veámoslo con un ejemplo continuando con lo anterior.</p>
<p>Lo primero vamos a crear otro constructor, en este caso <strong>SuperPowers()</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function SuperPowers(){
this.superStrength = function(){
console.log( this.alias + ' tiene super fuerza')
}
this.superSpeed = function(){
console.log( this.alias + ' tiene super velocidad')
}
}
</code></pre></div>
<p>Y a continuación lo que haremos será <strong>"asignarle"</strong> estas propiedades a nuestro <strong>rorschach</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">Object.assign(rorschach, new SuperPowers());
</code></pre></div>
<p>Simplemente tenemos que usar el método <strong>assign</strong> de <strong>Object</strong> y como parámetros le pasamos la instancia del objeto destino y una instancia del objeto origen, en este caso con <strong>new SuperPowers()</strong></p>
<p>Ahora simplemente podemos comprobar que realmente nuestro <strong>rorschach</strong> tiene las propiedades de <strong>SuperPowers</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rorschach.superStrength();
rorschach.superSpeed();
</code></pre></div>
<p>Además le añadiremos lo mismo que antes para comprobar si es una instancia de <strong>SuperPowers</strong>, quedando así todo el código</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Herencia
function Superhero(alias) {
this.alias = alias;
this.getInfo = function () {
console.log('Nuestro héroe se llama ' + this.alias);
}
}
var mr_manhattan = new Superhero('Dr. Manhattan');
mr_manhattan.getInfo();
//Herencia de superhero
function Hero(alias){
Superhero.call(this, alias);
}
Hero.prototype = new Superhero('Walter Joseph Kovacs');
var rorschach = new Hero('Rorschach');
rorschach.getInfo();
console.log(Object.getPrototypeOf(rorschach))
console.log('Es una instancia de Hero? ' + (rorschach instanceof Hero))
console.log('Es una instancia de SuperHero? ' + (rorschach instanceof Superhero))
//Herencia Múltiple
function SuperPowers(){
this.superStrength = function(){
console.log( this.alias + ' tiene super fuerza')
}
this.superSpeed = function(){
console.log( this.alias + ' tiene super velocidad')
}
}
Object.assign(rorschach, new SuperPowers());
rorschach.superStrength();
rorschach.superSpeed();
console.log('Es una instancia de SuperPowers? ' + (rorschach instanceof SuperPowers));
</code></pre></div>
<p>Lo que nos daría este resultado<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-13-at-09.00.25.png" alt="Don't stop the party: Node JS(IV) Hablemos un poco de JS (III)"/></br></p>
<p>Anda!!! Hay algo distinto verdad?? Nos dice que no es una instancia de <strong>SuperPowers</strong>...pero ¿por qué?.. Bueno en este caso es bastante simple, realmente lo que hacemos es una copia de propiedades de un elemento a otro, es decir, sería como si el constructor de nuestro <strong>rorschach</strong> hubiera tenido las mismas propiedades que <strong>SuperPowers</strong>.</p>
<p>Y hasta aquí el repaso de algunos elementos de JavasScript, a partir del próximo post ya empezaremos a ver <strong>NodeJS</strong> (Por fiiiiiin!!!! ;) )</p>
<p>Nos vemoooossssss, un abrazooooooorrrr</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[React Superhero (IV): Estructura de proyecto base]]></title><description><![CDATA[En el post anterior creamos un proyecto de React usando el CLI que nos
proporcionan los creadores del mismo. Esta herramienta de linea de comandos nos
crea un proyecto base desde el que partir y como vimos cuando usamos npm start
para arrancar nuestro servidor de desarrollo, la herramienta nos muestra una
página similar a esta:
Veamos un poco la estructura del proyecto y desde donde podemos empezar a
trabajar.
Lo primero veamos lo que tenemos:
En lo primero que nos tenemos que fijar es en ]]></description><link>https://jlgarcia.fulldev.ninja/react-superhero-iv/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f29</guid><category><![CDATA[reactjs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 07 Sep 2017 08:26:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" alt="React Superhero (IV): Estructura de proyecto base"/><p>En el post anterior creamos un proyecto de <strong>React</strong> usando el <strong>CLI</strong> que nos proporcionan los creadores del mismo. Esta herramienta de linea de comandos nos crea un proyecto base desde el que partir y como vimos cuando usamos <strong>npm start</strong> para arrancar nuestro servidor de desarrollo, la herramienta nos muestra una página similar a esta:</p>
<p><img srcset="/assets/images/2017/09/Screen-Shot-2017-09-04-at-09.26.57.png" alt="React Superhero (IV): Estructura de proyecto base"/></p>
<p>Veamos un poco la estructura del proyecto y desde donde podemos empezar a trabajar.<br>
Lo primero veamos lo que tenemos:<br>
<img srcset="/assets/images/2017/09/Screen-Shot-2017-09-04-at-09.29.33.png" alt="React Superhero (IV): Estructura de proyecto base"/></br></br></p>
<p>En lo primero que nos tenemos que fijar es en los <strong>index</strong> tanto el <strong>js</strong>, como el <strong>html</strong>, ya que son desde donde se empieza a llamar al resto. Si miramos el <strong>index.html</strong> tenemos una pagina html con varios tags pero lo que nos importa realmente es algo que ya hemos visto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> <div id="root"></div>
</code></pre></div>
<p>Recordemos que es en ese punto donde se empieza a componer nuestra aplicación.</p>
<p>Lo siguiente miremos dentro de la carpeta <strong>src</strong> y veamos el <strong>index.js</strong> que aqui tenemos varias cosas interesantes:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
</code></pre></div>
<p>Tenemos varios imports, luego el típico <strong>ReactDOM.render</strong> y por último una llamada a un método <strong>registerServiceWorker()</strong>. Comencemos con los <strong>imports</strong>, los dos primeros ya los hemos visto antes, son los específicos para que React funcione, veamos los siguientes:</p>
<ul>
<li><strong>"import './index.css';"</strong>: No es muy especial solo importa el css, ni más ni menos.</li>
<li><strong>"import App from './App';"</strong> : Este import nos instancia el componente que está dentro del fichero <strong>App.js</strong>, un poco más abajo hablaremos como está creado esto, es algo parecido a node con los exports ;).</li>
<li><strong>"import registerServiceWorker from './registerServiceWorker';"</strong>: Este import realemente es el que instancia el servidor local y anda pendiente de los cambios en el código, lo que hace es cargar el export por defecto. Si alguién tiene dudas con el código de este fichero que lo ponga en comentarios y lo vemos ;).</li>
</ul>
<p>A continuación como ya hemos comentado, tenemos nuestro típico render de react que lo que hace es instanciar el componente <strong>App</strong>. Si miramos el código de <strong>App.js</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}
export default App;
</code></pre></div>
<p>Vemos que ya hemos visto muchas cosas, comentar que los imports de <strong>logo</strong> y de <strong>App.css</strong> los necesitamos para usarlos en nuestro código JSX, si os fijáis en la línea:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><img src={logo} className="App-logo" alt="logo" />
</code></pre></div>
<p>Tenemos las dos cosas, usamos el <strong>logo</strong> dentro de src y ya estamos usando tambien nombres de clases del fichero css.</p>
<p>En este punto faltaría solo comentar la última y casi la más importante del conjunto (en este punto jejeje):</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">export default App;
</code></pre></div>
<p>Esta línea lo que indica es que por defecto cuando se haga un import de este fichero se importe el componente <strong>App</strong>. Un detalle importante, <strong>sin export no importamos nada</strong>, si comentáramos esa línea tendríamos este resultado:</p>
<p><img srcset="/assets/images/2017/09/Screen-Shot-2017-09-04-at-21.42.51.png" alt="React Superhero (IV): Estructura de proyecto base"/></p>
<p>Creo que más o menos se entiende todo, solo comentar que si quisieramos cambiar el componente <strong>App</strong> por otro solo tendríamos que crear el componente como queramos ponerle la línea <strong>export</strong> y cambiar el <strong><app/></strong> dentro del <strong>ReactDOM.render</strong> como ya hemos visto en algún post anterior (de todas formas iremos trabajando con esto más de una vez ;) ).</p>
<p>Como vemos prácticamente todo lo haremos dentro de la carpeta <strong>src</strong> y sigue manteniendo el nivel de sencillez que hemos estado viendo.</p>
<p>Sin mucho más nos vemos en el siguiente. Un abrazoooooooo</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(III) Hablemos un poco de JS (II)]]></title><description><![CDATA[Closures
Un closure es una función que devuelve otra función, teniendo la segunda acceso
a los datos de la primera, es decir comparten contexto.
Veamos un ejemplo sencillo
function heroName(surname){
return function(name){
console.log(name + ' ' + surname);
}
}
var dr_Manhattan = heroName('Osterman');
console.log(dr_Manhattan('Jon'));
Como veis el concepto es bastante sencillo, lo primero instanciamos heroName con
su parámetro surname como Osterman, eso lo que hace es asignar la func]]></description><link>https://jlgarcia.fulldev.ninja/node-js-iii-hablemos-un-poco-de-js-ii/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f21</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 04 Sep 2017 08:06:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="closures">Closures</h2>
<img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" alt="Don't stop the party: Node JS(III) Hablemos un poco de JS (II)"/><p>Un <strong>closure</strong> es una función que devuelve otra función, teniendo la segunda acceso a los datos de la primera, es decir comparten contexto.<br>
Veamos un ejemplo sencillo</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function heroName(surname){
return function(name){
console.log(name + ' ' + surname);
}
}
var dr_Manhattan = heroName('Osterman');
console.log(dr_Manhattan('Jon'));
</code></pre></div>
<p>Como veis el concepto es bastante sencillo, lo primero instanciamos <strong>heroName</strong> con su parámetro <strong>surname</strong> como <em>Osterman</em>, eso lo que hace es asignar la función que retorna a la variable <strong>dr_Manhattan</strong>, por lo que ahora mismo <strong>dr_Manhattan</strong> se ha convertido en un método que espera recibir un nombre por parámetro y que en su contexto tiene acceso al parámetro <strong>surname</strong>.<br>
Tambien podemos devolver varias funciones no solo una, vamos a cambiar un poco nuestra función de retorno:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function heroName(surname){
return {
getHeroData: function(name){
console.log(name + ' ' + surname);
},
setHeroNewName: function(newName){
name = newName;
},
setHewNewSurname: function(newSurname){
surname = newSurname;
}
}
}
</code></pre></div>
<p>Ahora ya no podemos usarla igual que antes, estamos devolviendo objetos, por lo que tenemos que llamarlos. Lo primero vamos a usar la que seria homónima a la de antes, se decir después de la nueva función ponemos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var dr_Manhattan = heroName('Osterman');
dr_Manhattan.setHeroNewName('Jon');
dr_Manhattan.getHeroData();
</code></pre></div>
<p>Esta nos devuelve lo mismo de antes. Como vemos ahora la variable <strong>dr_Manhattan</strong> funciona como una clase con varios métodos(en este caso lo hemos planteado como métodos GETTER y SETTER). Ahora vamos a ver que pasa si usamos el resto, añadimos a continuación:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">dr_Manhattan.setHeroNewName('Doctor');
dr_Manhattan.setHewNewSurname('Manhattan');
dr_Manhattan.getHeroData();
</code></pre></div>
<p>Con obtendríamos estos resultados:<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-12-at-12.35.09.png" alt="Don't stop the party: Node JS(III) Hablemos un poco de JS (II)"><br>
Como vemos hemos creado una especie de constructor <em>Héroes</em> de una manera relativamente sencilla.</br></img></br></p>
<h2 id="prototypes">Prototypes</h2>
<p>Bien lo siguiente que veremos serán los prototypes. ¿Que es un <strong>prototype</strong>? Un prototype es una propiedad que tienen todos los objetos de JavaScript(y como casi todo es considerado un objeto son muchas cosas jejejej) y que comparten los que son del mismo del mismo tipo aunque ya hayan sido creados. Dentro de un prototype podemos tener casi de todo. Veamos un ejemplo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Tenemos un constructor en este caso de clones
//del Dr.Manhattan
function dr_Manhattan_Clone(cloneNumber){
this.cloneName = 'clon' + cloneNumber;
}
</code></pre></div>
<p>Para que veamos que este constructor (que es un objeto) ya tiene la propiedad <strong>prototype</strong> hagamos un console.log para ver que tiene</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">console.log(dr_Manhattan_Clone.prototype)
</code></pre></div>
<p>Esto nos mostrará<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.49.27.png" alt="Don't stop the party: Node JS(III) Hablemos un poco de JS (II)"><br>
No tiene nada pero hemos comprobado que por lo menos no da error, es decir, que <strong>es una propiedad válida de nuestro objeto</strong><br>
Ahora creemos un par de clones y mostremos su nombre o número de clon</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var cloneOne = new dr_Manhattan_Clone(1);
var cloneTwo = new dr_Manhattan_Clone(2);
console.log(cloneOne.cloneName);
console.log(cloneTwo.cloneName);
</code></pre></div>
<p>Todo normal<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.52.38.png" alt="Don't stop the party: Node JS(III) Hablemos un poco de JS (II)"><br>
Por cierto antes de seguir en este caso iremos acumulando código e iremos viendo todo el log desde el principio.<br>
Bueno en la última imagen hemos visto que teniamos el nombre de nuestros clones como era de esperar. Veamos ahora que tienen nuestros clones</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">console.log(cloneOne);
console.log(cloneTwo);
</code></pre></div>
<p><img srcset="/assets/images/2017/08/Screen-Shot-2017-08-12-at-13.54.38.png" alt="Don't stop the party: Node JS(III) Hablemos un poco de JS (II)"><br>
Bien como vemos son objetos de tipo <em>dr_Manhattan_Clone</em> que tienen una propiedad <em>cloneName</em> con su nombre o número.<br>
Todo normal hasta aquí no?<br>
Ahora creemos nuestro primer prototipo, decimos que clon tiene conocimiento sobre la materia y cual no(haremos uno un poco menos listo :P )</br></br></br></img></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">dr_Manhattan_Clone.prototype.matterCrontol = function(matter){
this.matterKnowledge = matter;
}
</code></pre></div>
<p>He creado un prototipo llamado <strong>matterCrontol</strong> que básicamente espera que le digamos si el clon tiene conocimiento de la materia o no. Vamos a ver que tiene ahora la propiedad prototype de nuestro constructor</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">console.log(dr_Manhattan_Clone.prototype)
</code></pre></div>
<p><img srcset="/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.08.44.png" alt="Don't stop the party: Node JS(III) Hablemos un poco de JS (II)"><br>
Vaya si nos fijamos en la primera y la última línea vemos como ahora sí tenemos algo dentro de la propiedad <strong>prototype</strong> de nuestro constructor.<br>
Bien pues si la teoría es correcta nuestros clones ya creados deberían poder usar esta propiedad, pues comprobemoslo</br></br></img></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">cloneOne.matterCrontol(true);
cloneTwo.matterCrontol(false);
console.log(cloneOne);
console.log(cloneTwo);
</code></pre></div>
<p>Si ejecutamos vemos como no se queja, si no que ademas ahora nuestros clones tienen otra propiedad más que ha sido asignada al ejecutar el método <strong>matterControl</strong> en cada clon.<br>
Como tal podríamos seguir asignando prototypes a nuestro constructor y lo tendríamos disponible en todas nuestras instancias de clones. Todo esto se parece un poco a la <strong>herencia</strong> de otros lenguajes no??</br></p>
<p>Bueno puede que a lo mejor no le veáis muchísima utilidad, pero y si os digo que <strong>podemos asignar prototypes a objetos propios de JavaScript como al objeto Array por ejemplo??</strong><br>
Miremos primero el objeto <a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array"><strong>Array</strong></a>, si nos fijamos en la parte izquierda podemos ver que realmente todos los métodos que usamos en los objetos <strong>¡¡son prototypes!!</strong>, por lo que solo tendríamos que añadir otro <strong>prototype</strong> al objeto array para que lo tengan todos.</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">Array.prototype.sum = function(){
return this.map(function(x){
return x + 5;
})
}
</code></pre></div>
<p>Bien he creado un protoype <strong>sum</strong>, que recorre todos los números de un array y le suma 5.<br>
Si la teoría es cierta, ahora cualquier array que creemos podrá usar esa propiedad</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var numbers = [1,2,3,4,5];
var result = numbers.sum();
console.log(result);
</code></pre></div>
<p>Y si ejecutamos vemos como si que funciona<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.36.31.png" alt="Don't stop the party: Node JS(III) Hablemos un poco de JS (II)"><br>
Probemos con otro array</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var numbers = [1,2,3,4,5];
var result = numbers.sum();
console.log(result);
var numbers2 = [5,10,15,20,25];
console.log(numbers2.sum());
</code></pre></div>
<p>Y el resultado es<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-12-at-14.38.15.png" alt="Don't stop the party: Node JS(III) Hablemos un poco de JS (II)"><br>
Pues como veis ahora podemos usar ese método en todos nuestros arrays, por lo que realmente puede llegar a ser muy útil para ciertos entornos donde necesitamos que muchos objetos de repente tengan que hacer algo que antes no hacian, incluso <strong>nos puede servir para generalizar métodos y que varios objetos puedan usar el mismo método</strong> (pero esto lo dejaremos para otra ocasión)<br>
Ya va quedando poco para empezar a trabajar con Node no os preocupéis.<br>
Nos vemooossssssss.</br></br></br></img></br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[React Superhero (III): Entorno de desarrollo]]></title><description><![CDATA[Bien antes de ponernos serios desarrollando algo más complejo con React,
necesitamos configurar nuestro entorno ya que una app de React necesita de
varias dependencias para funcionar correctamente en producción(además que nos
facilitan un poco el ir desarrollando).
Hasta hace poco, con React debíamos hacer toda la configuración y preparación
del entorno a mano, pero nuestros amigos de Facebook, se han creado una especie
de atajo al estilo AngularCLI(más info Create React APP
[https://github.com]]></description><link>https://jlgarcia.fulldev.ninja/react-js-iii-entorno-de-desarrollo/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f1d</guid><category><![CDATA[reactjs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 28 Aug 2017 08:03:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" alt="React Superhero (III): Entorno de desarrollo"/><p>Bien antes de ponernos serios desarrollando algo más complejo con React, necesitamos configurar nuestro entorno ya que una app de React necesita de varias dependencias para funcionar correctamente en producción(además que nos facilitan un poco el ir desarrollando).</p>
<p>Hasta hace poco, con React debíamos hacer toda la configuración y preparación del entorno a mano, pero nuestros amigos de Facebook, se han creado una especie de atajo al estilo <strong>AngularCLI</strong>(más info <a href="https://github.com/facebookincubator/create-react-app">Create React APP</a>), para usarlo lo primero es instalar <a href="https://nodejs.org/es/">NodeJS</a>, es suficiente con instalar la versión <strong>LTS</strong> desde la página principal, para el que no lo sepa NodeJS es la opción servidor de JS, es orientado a eventos lo que le permite manejar un gran número de peticiones, por el momento no voy a entrar mucho en esto, tengo intención de crear una linea de post solo de Node por lo que si os interesa estar atentos ;).</p>
<p>Una vez instalado podemos comprobar que se ha instalado correctamente con las siguientes instrucciones en nuestra consola de comandos preferida:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">#Para ver la versión de NodeJS
node -v
#La versión de Node Package Manager
npm -v
</code></pre></div>
<p><img srcset="/assets/images/2017/08/Screen-Shot-2017-08-04-at-08.54.25.png" alt="React Superhero (III): Entorno de desarrollo"><br>
Yo simplemente he encadenado los comandos pero os debería salir algo similar a eso.</br></img></p>
<p>Bien lo primero de todo es hacer que <strong>NPM</strong> instale los paquetes que necesitamos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">npm -g install create-react-app
</code></pre></div>
<p>Es tan sencillo como indicarlo con el nombre, y el <strong>-g</strong> es para que nos lo instale globalmente y podamos usarlo en cualquier sitio, si no lo pusieramos solo nos lo instalaría en el directorio donde estuviéramos trabajando en la linea de comandos. Una vez ejecutado se descargará y configurará algunas cosas el solito, veréis unas cuantas líneas como estas:<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.03.41.png" alt="React Superhero (III): Entorno de desarrollo"><br>
Bien una vez instalado ya podemos crear nuestro entorno para la app que vamos a desarrollar, para ello solo necesitamos llamar a nuestro nuevo comando he indicarle al nombre de la app que deseamos crear:</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">create-react-app nuclear_superhero_app
</code></pre></div>
<p>Una vez terminado el proceso nos saldrá algo similar a esto<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.08.17.png" alt="React Superhero (III): Entorno de desarrollo"><br>
Por último para empezar a ver la utilidad de esto tenemos que hacer lo que nos sugieren al final, entrar en el directorio y ejecutar <strong>start</strong>:</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">cd nuclear_superhero_app
npm start
</code></pre></div>
<p>Si todo ha ido bien se os habrá abierto otra pestaña en el navegador con esto:<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-04-at-09.11.31.png" alt="React Superhero (III): Entorno de desarrollo"/></br></p>
<p>Básicamente nos ha levantado un "servidor" en local en el puerto 3000 donde podremos ir viendo los cambios en nuestra aplicación casi en tiempo real. Si queremos para el servidor es suficiente con irnos a la consola desde donde lo hemos lanzado y detener el proceso con <strong>ctrl+c</strong> o como soláis hacerlo.</p>
<p>Con esto ya tendríamos lo que necesitamos para empezar a trabajar realmente con React, que es lo que haremos desde el próximo post, si alguien ha tenido problemas o quiere saber algo de Node que lo ponga en comentarios y lo vamos viendo.Nos vemoooossssss.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS(II) Hablemos un poco de JS (I)]]></title><description><![CDATA[Para poder trabajar bien con Node vamos a continuar repasando varias cosas de
JavaScript, pensando sobretodo en no tener problemas con funciones o métodos
complejos de Node.
Empecemos con THIS
Vamos a ver un poco para que usamos esta palabra reservada.
Tenemos dos casos típicos donde nos podemos encontrar this:
* El primero sería dentro de un método o función. En este caso this haría
referencia a la instanciación de ese método, veamos un ejemplo:
var superhero = {
name: 'Jonathan Osterm]]></description><link>https://jlgarcia.fulldev.ninja/node-js-ii-hablemos-un-poco-de-js-i/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f20</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 24 Aug 2017 08:03:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" alt="Don't stop the party: Node JS(II) Hablemos un poco de JS (I)"/><p>Para poder trabajar bien con Node vamos a continuar repasando varias cosas de JavaScript, pensando sobretodo en no tener problemas con funciones o métodos complejos de Node.</p>
<h3 id="empecemosconthis">Empecemos con THIS</h3>
<p>Vamos a ver un poco para que usamos esta palabra reservada.<br>
Tenemos dos casos típicos donde nos podemos encontrar <strong>this</strong>:</br></p>
<ul>
<li>El primero sería dentro de un método o función. En este caso <strong>this</strong> haría referencia a la instanciación de ese método, veamos un ejemplo:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var superhero = {
name: 'Jonathan Osterman',
alias: 'Dr. Manhattan',
getInfo: function() {
console.log(this.name + ' se convirtió en el ' + this.alias);
}
}
superhero.getInfo();
</code></pre></div>
<p>Como veis usamos <strong>this</strong> para acceder a los datos dentro de superhero cuando llamamos a la función <strong>getInfo</strong>, sin <strong>this</strong> obtendríamos este error<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-09-at-09.37.11.png" alt="Don't stop the party: Node JS(II) Hablemos un poco de JS (I)"><br>
Sin this no tenemos acceso al contexto en el que estamos funcionando.</br></img></br></p>
<ul>
<li>El segundo caso es cuando lo usamos fuera de un método. En este caso <strong>this</strong> tendria la información del contexto global o si estamos en modo estricto que seria undefined (cuando ponemos 'use strict' al inicio de nuestra clase teneis info aqui <a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Modo_estricto">Modo Estricto</a>)<br>
Veamos un ejemplo(sin modo estricto)</br></li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var superhero = {}
this.superhero = {
name: 'Jonathan Osterman',
alias: 'Dr. Manhattan',
getInfo: function () {
console.log(this.name + ' se convirtió en el ' + this.alias)
}
}
console.log(this)
</code></pre></div>
<p>En este caso hemos introducido en el this del contexto global la propiedad <strong>superhero</strong>, que al hacerlo así tenemos que declararla primero, y si vemos el resultado vemos como ahora this tiene ese objeto<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-09-at-09.48.09.png" alt="Don't stop the party: Node JS(II) Hablemos un poco de JS (I)"><br>
Si lo ejecutaramos en un navegador veríamos como <strong>this</strong> en el contexto global contiene el objeto <strong>window</strong> que tiene un montón de información de la página web donde lo hayamos lanzado<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-09-at-09.49.20.png" alt="Don't stop the party: Node JS(II) Hablemos un poco de JS (I)"/></br></br></img></br></p>
<p>Bien ahora ya sabemos un poco que pasa con <strong>this</strong> en el contexto global y dentro de un método o función, pero ¿que pasaría si nuestra función <strong>getInfo</strong> fuera un callback de otra, es decir que realmente la hemos pasamos por parámetro? Hagamos la prueba con <strong>setTimeout</strong>, que como sabemos ejecuta lo que le pasemos por parámetro en el tiempo que le indiquemos, debajo de lo que ya teníamos añadimos</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">setTimeout(this.superhero.getInfo,500);
</code></pre></div>
<p>Y ejecutamos(ya sabéis con <strong>node nombreFichero.js</strong>)<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-09-at-21.08.39.png" alt="Don't stop the party: Node JS(II) Hablemos un poco de JS (I)"><br>
Vaya!! no es no lo que esperabamos, ¿verdad?....y esto ¿por qué?.....bueno pensemos lo siguiente el this dentro de una función representa al contexto que lo ha llamado, en nuestro caso <strong>this</strong> tendría la información del contexto de <strong>setTimeout</strong>, para que lo veáis un poco más claro cambiar el código dentro de la función por lo siguiente:</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var superhero = {}
this.superhero = {
name: 'Jonathan Osterman',
alias: 'Dr. Manhattan',
getInfo: function () {
console.log(this)
//console.log(this.name + ' se convirtió en el ' + this.alias)
}
}
console.log(this)
setTimeout(this.superhero.getInfo, 500)
</code></pre></div>
<p>Si os fijáis he comentado nuestra linea con <em>this.name</em> y <em>this.alias</em> y he puesto solo un log con this, el resultado que deberíais ver sería similar a este<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-09-at-21.15.23.png" alt="Don't stop the party: Node JS(II) Hablemos un poco de JS (I)"><br>
Como veis nuestro <strong>this</strong> es muy distinto de lo que esperabamos, tiene información solo relativa a nuestro <strong>setTimeout</strong>. Y, ¿cómo lo solucionamos? Es relativamente sencillo, lo que tenemos que hacer es <em><strong>"enlazar"</strong></em> el this que nosotros queramos y eso lo hacemos usando la propiedad <strong>bind</strong> y le pasamos nuestro propio this.</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">setTimeout(this.superhero.getInfo.bind(this), 500)
</code></pre></div>
<p>Si ejecutamos ahora lo que teníamos<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-09-at-21.19.44.png" alt="Don't stop the party: Node JS(II) Hablemos un poco de JS (I)"><br>
Vemos como el this es el mismo dentro y fuera de <strong>setTimeout</strong>, ahora solo tenemos que eliminar el log del this dentro de la función, descomentar la línea y.......si nos falta otra cosa como tal hemos <em>enlazado</em> nuestro this, pero esto realmente es el objeto completo para que realmente nos funcione como antes debemos pasarle el objeto <strong>superhero</strong></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">setTimeout(this.superhero.getInfo.bind(this.superhero), 500)
</code></pre></div>
<p>Y <strong>ahora sí</strong> tenemos nuestra función devolviendo lo que esperábamos dentro de <em>setTimeout</em><br>
Espero que esto quede más o menos claro, así me lo explicaron a mí los magos de <a href="https://keepcoding.io/es/">KeepCoding</a> y creo que es la mejor manera.</br></p>
<p>Lo último que veremos en este post serán las funciones constructoras(que también usan this ;) )<br>
Como ya hemos visto varias cosas pongo un código un pelín más largo, con una función constructora y dos instancias de ésta, con sus dos <strong>setTimeout</strong></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">function superhero() {
this.name;
this.alias;
this.getInfo = function () {
console.log(this.name + ' se convirtió en ' + this.alias);
}
}
var mr_manhattan = new superhero();
mr_manhattan.name = 'Jon Osterman';
mr_manhattan.alias = 'Dr. Manhattan';
mr_manhattan.getInfo();
var loki = new superhero();
loki.name = 'Loki Laufeyson';
loki.alias = 'Loki'
loki.getInfo();
setTimeout(mr_manhattan.getInfo, 500);
setTimeout(loki.getInfo, 500);
</code></pre></div>
<p>Bueno más o menos os imaginareis como es una función constructora no? Una función que con ayuda del this representa cada propiedad del objeto instanciado y la mantiene solo en ese objeto.<br>
Si ejecutamos esto tenemos lo siguiente<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-09-at-21.58.31.png" alt="Don't stop the party: Node JS(II) Hablemos un poco de JS (I)"><br>
Como vemos tenemos el mismo problema que antes, asi que vamos a usar nuestro conocido bind pasándole a cada uno su objeto pertinente</br></img></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">setTimeout(mr_manhattan.getInfo.bind(mr_manhattan), 500);
setTimeout(loki.getInfo.bind(loki), 500);
</code></pre></div>
<p>Y vemos como el resultado ya es el que nos interesa<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-09-at-22.00.27.png" alt="Don't stop the party: Node JS(II) Hablemos un poco de JS (I)"><br>
Bien con esto aparte de repasar un poco una función constructora rápidamente quería que vierais que el concepto del bind es el mismo para la mayoría de las situaciones en la que nos encontremos. Recordad si tenéis <strong>undefinided</strong> en algún método pensar en <strong>BIND</strong>.</br></img></br></p>
<p>Sin mucho más nos vemos en el siguiente. Ciaaooooo</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[React Superhero (II): Cambios entre componentes]]></title><description><![CDATA[En este post veremos como pasar datos o más bien como comunicarnos entre
componentes. Para ello partiendo de lo que tenemos del post anterior:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<!-- Libreria para trabajar con React -->
<script src="https://unpkg.com/react@latest/dist/react.js"></script>
<!-- Libreria de react para trabajar con el Dom-->
<script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
<!--P]]></description><link>https://jlgarcia.fulldev.ninja/react-js-ii-cambios-entre-componentes/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f1c</guid><category><![CDATA[reactjs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 21 Aug 2017 08:01:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" alt="React Superhero (II): Cambios entre componentes"/><p>En este post veremos como pasar datos o más bien como comunicarnos entre componentes. Para ello partiendo de lo que tenemos del post anterior:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<!-- Libreria para trabajar con React -->
<script src="https://unpkg.com/react@latest/dist/react.js"></script>
<!-- Libreria de react para trabajar con el Dom-->
<script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
<!--Preprocesador para traducir lo que escribimos a todos los navegadores ya que react funciona con ECS6 y puede que no
funcione en todos -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<script type="text/babel">
class SuperComponente extends React.Component{
constructor(){
super();
}
render(){
return (
<div>
<h2>Hello with React</h2>
<MiSegundoComponente/>
</div>
);
}
}
class MiSegundoComponente extends React.Component{
constructor(){
super();
this.state = {
nombre: "Your Super Name"
}
}
getName(input){
this.setState({nombre: input.target.value});
}
render(){
return (
<div>
<h2>REACT is in the HOUSE...YEAH!!!!</h2>
<input onChange={this.getName.bind(this)}></input>
<h4> { this.state.nombre } </h4>
</div>
)
}
}
ReactDOM.render(
<SuperComponente/>,
document.getElementById('root')
);
</script>
</head>
<body>
<div id="root"></div>
</body>
</html>
</code></pre></div>
<p>Vamos a crear otro componente que usaremos para hacer que un numero aumente, es decir vamos a sumarle uno, es un ejemplo muy simple pero suficiente para ver los conceptos que queremos, por el momento lo primero sera crear el componente con un botón y un elemento para mostrar el nùmero</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class PlusOneNumber extends React.Component {
render(){
return (
<div>
<p>0</p>
<button>AumentarNumero</button>
</div>
)
}
}
</code></pre></div>
<p>Bien y lo ponemos en nuestro componente principal para que lo muestre, a continuación del que era <strong>MiSegundoComponente</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">render(){
return (
<div>
<h2>Hello with React</h2>
<MiSegundoComponente/>
<PlusOneNumber/>
</div>
);
}
</code></pre></div>
<p>Bien ahora mismo ya se tendría que mostrar, pero esto como tal no hace nada ni el botón ni el 0, vamos a empezar a darle "vida" a nuestro componente en conjunto con el componente principal.<br>
Lo primero que hacemos es crear un constructor con una propiedad en el componente principal, algo así:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class SuperComponente extends React.Component{
constructor(){
super();
this.state = {
number: 0
}
}
render(){
return (
<div>
<h2>Hello with React</h2>
<MiSegundoComponente/>
<PlusOneNumber/>
</div>
);
}
}
</code></pre></div>
<p>Lo que tenemos dentro de <strong>this.state</strong> será lo que iremos cambiando cada vez que pulsemos el botón, es decir la idea es que el componente <strong>PlusOneNumber</strong> tome el valor de número desde el componente principal y le sume uno. ¿Pero como empezamos con esto?</p>
<p>Lo primero es pasar el valor desde el componente principal a nuestro componente que realiza la suma, para ello es tan simple como "pasarselo como una propiedad al componente":</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><h2>Hello with React</h2>
<MiSegundoComponente/>
<PlusOneNumber number={this.state.number}/>
</code></pre></div>
<p>Con esto lo mandamos al componente, y para acceder a este número desde nuestro componente auxiliar:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class PlusOneNumber extends React.Component {
render(){
return (
<div>
<p>{this.props.number}</p>
<button>AumentarNumero</button>
</div>
)
}
}
</code></pre></div>
<p>Como veis es suficiente con acceder a las propiedades de this en lugar de a su estado. Si ahora cargáis de nuevo la página veréis que todo sigue "igual", o casi, la diferencia es que ya está cogiendo el número desde el componente principal.</p>
<p>Siguiente paso, <strong>Aumentar el número</strong>, para ello lanzo una pregunta, ¿creéis que ahora que tenemos acceso podemos modificar esa propiedad en nuestro componente? Y hablo directamente la propiedad no de hacer un +1 en conjunto del <strong>this.props.number</strong>, ni tampoco de asignarla a una propiedad de este componente y trabajar desde aquí, me refiero a directamente modificar esa propiedad.....<strong>Pues No</strong>, y ¿por qué?, pues porque realmente el dueño o propietario de ese objeto es el componente principal no nuestro componente que realiza la suma. Es como si en <strong>POO</strong> tuviéramos una variable de clase que para cambiarla necesitamos usar un método setter(más o menos) y con esta pista veamos que tenemos que hacer para crear nuestro "setter".</p>
<p>Primero creamos una función en nuestro componente principal que realizará la suma:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">plusOne(){
this.setState({number: this.state.number + 1 })
}
</code></pre></div>
<p>Como hemos comentado anteriormente usamos <strong>setState</strong> para cambiar valores y simplemente le sumamos uno.<br>
A continuación queremos que el button haga algo, por lo que tendríamos que indicarle un <strong>onClick</strong> en algún sitio como suele ser en asuntos relacionados con JS y queremos que ese onClick de alguna manera use el método <strong>plusOne()</strong>, pero ¿como hacemos que nuestro componente auxiliar pueda usar ese método? Pues de la misma manera que hemos conseguido que reciba la propiedad número, lo único que en lugar de pasarle una propiedad o un estado le pasamos una función:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> <MiSegundoComponente/>
<PlusOneNumber number={this.state.number} funAumentar={this.plusOne.bind(this)}/>
</code></pre></div>
<p>Ahora la propiedad <strong>funAumentar</strong> contiene la función o método <strong>plusOne</strong> y recordemos que es necesario "enlazar"(bind) el contexto en el que trabajamos(el this vamos) para que todos tengan la información que necesitan, y por ultimo solo necesitamos decirle al button lo que tiene que hacer cuando lo pulsen en su propiedad <strong>onClick</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><p>{this.props.number}</p>
<button onClick={this.props.funAumentar}>AumentarNumero</button>
</code></pre></div>
<p>Y ya lo tenemos si ahora recargamos nuestra página tendremos lo siguiente, con un número que crece cada vez que lo pulsamos:<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-02-at-22.03.14.png" alt="React Superhero (II): Cambios entre componentes"><br>
Y como podréis comprobar el componente del post anterior también funciona.<br>
Para asentar un poco y confirmar que un componente realmente se comunica con otro, vamos a añadir lo siguiente en el componente principal:</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> <h2>Hello with React</h2>
<MiSegundoComponente/>
<PlusOneNumber number={this.state.number} funAumentar={this.plusOne.bind(this)}/>
<h4>{this.state.number}</h4>
</code></pre></div>
<p>Como veis he puesto directamente la propiedad <strong>number</strong> que tiene nuestro <strong>SuperCompomente</strong>, para que veaís que realmente si se esta modificando el número de este componente:<br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-02-at-22.16.33.png" alt="React Superhero (II): Cambios entre componentes"><br>
Bueno como veis es relativamente sencillo compartir información entre componentes, en los próximos post ya empezaremos a ponernos más serios.<br>
Nos vemooosssss</br></br></img></br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Don't stop the party: Node JS (I)]]></title><description><![CDATA[Comienzo otra nueva sección también dedicada al mundo JavaScript en este caso de
NodeJS pero...
¿Que es NodeJS?
Bien en este caso la mejor explicación corta es la de la página oficial de
NodeJS [https://nodejs.org/es/]:
> Node.js® es un entorno de ejecución para JavaScript construido con el motor de
JavaScript V8 de Chrome. Node.js usa un modelo de operaciones E/S sin bloqueo y
orientado a eventos, que lo hace liviano y eficiente. El ecosistema de paquetes
de Node.js, npm, es el ecosistema m]]></description><link>https://jlgarcia.fulldev.ninja/dont-stop-the-party-node-js-i/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f1e</guid><category><![CDATA[nodejs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 17 Aug 2017 08:19:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ebae59fce798d71ce68bf2a304f1491f/nodebaner.jpg" alt="Don't stop the party: Node JS (I)"/><p>Comienzo otra nueva sección también dedicada al mundo JavaScript en este caso de <strong>NodeJS</strong> pero...</p>
<h2 id="queesnodejs">¿Que es NodeJS?</h2>
<p>Bien en este caso la mejor explicación corta es la de la página oficial de <a href="https://nodejs.org/es/">NodeJS</a>:</p>
<blockquote>
<p>Node.js® es un entorno de ejecución para JavaScript construido con el motor de JavaScript V8 de Chrome. Node.js usa un modelo de operaciones E/S sin bloqueo y orientado a eventos, que lo hace liviano y eficiente. El ecosistema de paquetes de Node.js, npm, es el ecosistema mas grande de librerías de código abierto en el mundo.</p>
</blockquote>
<p>Para aclarar un poco NodeJS es la parte de backend de JavaScript y uno de sus puntos fuertes al ser <em>no bloqueante</em> (como dice arriba) es la concurrencia, es decir maneja peticiones sin detenerse o bloquear las que le llegan (tiene límites por supuesto) y esta orientado a eventos, que para el que no lo sepa este tipo de programación basa su funcionamiento en eventos o mensajes recibidos desde otros hilos, programas....desde donde sea.</p>
<p>Otro de sus puntos fuertes es <strong>npm</strong>, ¿y esto que es? bueno como hemos comentado arriba es el gestor de paquetes de código abierto más grande del mundo (orientados a JS), en el que podemos encontrar librerías de casi todo lo que se nos ocurra al ser <em>open-source</em> se beneficia de que cualquiera puede subir paquetes por lo que el límite es prácticamente la imaginación ;)</p>
<p>En un principio esta sección esta centrada solo en <strong>NodeJS</strong> pero en los primeros posts comentaré algunas características de JavaScript que nos ayudarán en el entendimiento del conjunto, de todas formas ya os adelanto que posiblemente haga alguna sección con pequeños trucos o ejemplos de uso de JS.<br>
Hablaremos de Node no de JS pero si explicaremos lo necesario para entender lo que estamos haciendo.</br></p>
<p>Veamos un poco de que va esto de Node.</p>
<h3 id="instalacin">Instalación</h3>
<p>No me voy a entretener en la instalación en la página oficial de <a href="https://nodejs.org/es/">Node</a> viene muy bien explicado lo que tenemos que hacer en cada plataforma (en el caso de que sea distinto de descargar e instalar jejejeje)<br>
Yo recomiendo instalar la versión <strong>LTS</strong> ya que es a la que van dando soporte a lo largo del tiempo, las nuevas pueden tener bugs o dar problemas, pero podéis probar si queréis jejeje.<br>
La instalación nos provee también de <strong>npm</strong> por lo que ya lo tendríamos también disponible para usarlo. Más adelante iremos viendo como usar npm y que tenemos que tener en cuenta de su uso.</br></br></p>
<p>Pues sin mucho más vamos a empezar por ver algo de JavaScript.</p>
<h3 id="callbacks">Callbacks</h3>
<p>En node todos los usos de entrada o salida deberían ser asíncronos (no deben bloquear el hilo principal que es el que gestiona ), y una gran parte de la ayuda la obtenemos de los callbacks. Y que son los callbacks, para explicarlo de forma sencilla podríamos decir que son funciones que estando en el ciclo de vida de otra se ejecutan al final, es decir, son funciones que se llaman al terminar otra y no antes(aprovechándonos muchas veces de la posibilidad de pasar funciones como parámetros), veamos un ejemplo de función asíncrona con callbacks, para ello nos ayudaremos de la función <strong>setTimeout</strong> que para el que no lo sepa nos da la posibilidad de ejecutar algo tras el periodo de tiempo que le indiquemos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">"use strict";
console.log('Empezamos');
function showAfter2Seconds(text, callbackFunc){
setTimeout(()=>{
console.log(text);
callbackFunc();
},2000);
}
showAfter2Seconds('Pasaron 2 segundos',()=>{
console.log('Soy el callback');
});
console.log('Estoy fuera de la función')
</code></pre></div>
<p>Para ejecutarlo solo tenemos que usar el comando <strong>node</strong> seguido del nombre de nuestro fichero js:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">node callbacks.js
</code></pre></div>
<p>Y tendriamos algo como esto:</p>
<p><img srcset="/assets/images/2017/08/callbackDemo.gif" alt="Don't stop the party: Node JS (I)"><br>
Como vemos primero nos muestra <strong>'Empezamos'</strong> y luego directamente vemos <strong>'Estoy fuera de la función'</strong> pero...¿por qué?. Bien esto de debe a como funciona la asincronía en sí, cuando trabajamos con asincronía tenemos que pensar que tenemos más de 1 trabajador jugando con nuestro código, tenemos el principal(el que manda) el que siempre curra y luego tenemos a los que este llama para que trabajen en segundo plano <strong>mientras el continua</strong>, es decir, cuando nuestro worker principal se encuentra con código asíncrono avisa a un compi para que lo haga y el continúa por donde estaba sin detenerse, por eso nos retorna el log que esta al final, porque el hilo principal ha llegado allí antes de que nuesto worker en segundo plano terminara. Pero claro esto no es tan simple como usar una función como parámetro y ya está, no nos confundamos, usar una función como parámetro y llamarla cuando nos interese es solo una ventaja del lenguaje que nos ayuda a evitar lo que se conoce como <strong>race condition</strong>, y que se ejecute nuestro código como nosotros queremos, si nosotros quitamos el <strong>setTimeout</strong> y ponemos otro tipo de función que nos detenga la ejecución lo que haría el código seria pararse en ese punto, devolver <strong>'Soy el callback'</strong> y a continuación nos mostraría nuestro log <strong>'Estoy fuera de la función'</strong>. En este caso lo que sucede es que <strong>setTimeout</strong> es una función <strong>asíncrona</strong> de por sí, es decir, cuando nuestro hilo principal se encuentra con esta función llama a algún compi disponible para que la ejecute y ya el compi es el responsable de lo que pase dentro de <strong>setTimeout</strong>, puede que sea un poco lioso y yo me haya extendido mucho en este punto pero es realmente <strong>IMPORTANTE</strong> entender esto para poder trabajar bien con <strong>NodeJS</strong>. Node comunmente se usa con una librería llamada <strong>async</strong>, la cual nos abstrae un poco de tener que hacer funciones como la que hemos visto arriba para usar asincronia, la documentación oficial esta muy bien explicada por lo que creo que es suficiente con que miréis un poco de que va <a href="https://caolan.github.io/async/">aquí</a>.</br></img></p>
<p>Bueno para empezar creo que es suficiente nos vemosss en el siguiente Ninjaaaassssssss</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[React Superhero (I): Cambios en un mismo componente]]></title><description><![CDATA[Vamos a empezar a ver donde está realmente la gracia de esta librería, lo que
vimos en el post de introducción bien lo podíamos tener con un poco de código
HTML de toda la vida. Ahora vamos a darle algo de dinamismo a nuestro código.
Teníamos este código al final de nuestro primer post:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<!-- Libreria para trabajar con React -->
<script src="https://unpkg.com/react@latest/dist/react.js"></script>
]]></description><link>https://jlgarcia.fulldev.ninja/react-js-i-cambios-en-un-mismo-componente/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f1b</guid><category><![CDATA[reactjs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 14 Aug 2017 11:11:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" alt="React Superhero (I): Cambios en un mismo componente"/><p>Vamos a empezar a ver donde está realmente la gracia de esta librería, lo que vimos en el post de introducción bien lo podíamos tener con un poco de código HTML de toda la vida. Ahora vamos a darle algo de dinamismo a nuestro código.<br>
Teníamos este código al final de nuestro primer post:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<!-- Libreria para trabajar con React -->
<script src="https://unpkg.com/react@latest/dist/react.js"></script>
<!-- Libreria de react para trabajar con el Dom-->
<script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
<!--Preprocesador para traducir lo que escribimos a todos los navegadores ya que react funciona con ECS6 y puede que no
funcione en todos -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<script type="text/babel">
class SuperComponente extends React.Component{
render(){
return (
<div>
<h2>Hello with React</h2>
<MiSegundoComponente/>
</div>
);
}
}
class MiSegundoComponente extends React.Component{
render(){
return (
<h2>REACT is in the HOUSE...YEAH!!!!</h2>
)
}
}
ReactDOM.render(
<SuperComponente/>,
document.getElementById('root')
);
</script>
</head>
<body>
<div id="root"></div>
</body>
</html>
</code></pre></div>
<p>Bien tenemos 2 componentes y los renderizamos dentro del <strong>body</strong> en nuestro div con id <strong>root</strong>, pues bien, vamos a añadir/modificar lo siguiente en nuestro <strong>MiSegundoComponente</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class MiSegundoComponente extends React.Component{
constructor(){
super();
this.name = {
nombre: "Your Super Name"
}
}
render(){
return (
<div>
<h2>REACT is in the HOUSE...YEAH!!!!</h2>
<h4> { this.name.nombre } </h4>
</div>
)
}
}
</code></pre></div>
<p>Lo que hacemos es crear un método <strong>constructor</strong> (OJO es palabra reservada no es que lo haya puesto yo), por el momento siempre llamamos a <strong>super</strong> (esencial para que se ejecute), y hacemos que nuestra instancia del componente (nuestro amigo <strong>this</strong>) tenga una propiedad <strong>name</strong>, que es un <strong>objeto de clave=valor</strong> en este caso con una key <strong>nombre</strong> con un texto. Asimismo en la parte de render entre <strong>{}</strong>, llamamos a <strong>this</strong>, es decir, a la instancia de nuestro componente, pasándole la propiedad y el key que hemos creado. <strong>ESTO SERIA PROPIO DE JSX</strong>, este superpoder nos permite añadir JS en nuestro código HTML. Si ahora ejecutamos esto:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-29-at-19.51.45.png" alt="React Superhero (I): Cambios en un mismo componente"><br>
Vemos como nos añade el contenido de la key nombre, "pues muy bien, y esto pa que cansino??" diréis...vale realmente <strong>Your superName</strong> es un placeholder, la idea es que ese texto cambie en algún momento.</br></img></br></p>
<p>Para ello necesitamos "escuchar algo en algún sitio" y hacérselo saber a nuestra propiedad nombre. Pero... ¿como hacemos esto? Muy fácil, vamos por partes, primero como "escuchamos":</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Añadimos un input con la propiedad onChange
<input onChange={}/>
<h4> { this.name.nombre } </h4>
</code></pre></div>
<p>Y esto que hace, básicamente envía los eventos de cambio de ese elemento a lo que tengamos dentro de <strong>{}</strong> y ¿que debemos poner dentro? pues como es costumbre un método que creemos a través de nuestra instancia(this):</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Fuera de render
getName(input){
console.log(input)
}
//Dentro de render
<input onChange={this.getName}></input>
<h4> { this.name.nombre } </h4>
</code></pre></div>
<p>Como véis tenemos un método <strong>getName</strong> que recibe algo por parámetro, y le pasamos dentro del <strong>onChange</strong>, nuestra instancia llamando al método getName. De momento le ponemos un <strong>console.log</strong> para que podamos ver que es lo que nos pasa cada vez que escribimos. Si guardamos y abrimos nuestro <strong>index.html</strong>, cada vez que escribamos algo en nuestro input, recibiremos algo del estilo a esto:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-29-at-20.18.10.png" alt="React Superhero (I): Cambios en un mismo componente"><br>
Es un objeto con nombre <strong>Proxy</strong> y mogollón de información. Es un estilo de elemento clásico de eventos(digo estilo), pero claro no es lo que realmente buscamos, como conseguimos el contenido de nuestro input:</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">getName(input){
console.log(input.target.value)
}
</code></pre></div>
<p>Esto lo habréis tenido que ver alguna vez ya, simplemente buscamos el <strong>value</strong> del <strong>target</strong> de nuestro elemento, y ahora nuesto console.log nos ofrece, esta información según escribimos:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-29-at-20.22.58.png" alt="React Superhero (I): Cambios en un mismo componente"><br>
Bien ya tenemos lo que necesitamos, ahora completemos la función para que nos modifique nuestro placeholder.</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">getName(input){
this.setState(this.name = {nombre: input.target.value});
}
</code></pre></div>
<p>Para modificar "el estado" de un objeto o elemento del DOM tenemos el método o propiedad <strong>setState</strong>, el cual modificaría solo lo que le pasemos entre <strong>()</strong>.<br>
Teóricamente sería algo como esto, pero lo habéis probado? Si lo probáis veréis que no funciona,nos indica que this es <strong>undefined</strong><br>
<img srcset="/assets/images/2017/08/Screen-Shot-2017-08-02-at-08.33.45.png" alt="React Superhero (I): Cambios en un mismo componente"><br>
pero.....¿por qué? Básicamente porque <strong>this</strong> no está disponible como propiedad u objeto de las funciones o métodos que nosotros mismos creamos, para hacer que funcione es necesario <strong>enlazar(bind)</strong> el this con el contexto de ejecución. Para ello solo seria necesario hacer el siguiente cambio:</br></img></br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><div>
<h2>REACT is in the HOUSE...YEAH!!!!</h2>
<input onChange={this.getName.bind(this)}></input>
<h4> { this.name.nombre } </h4>
</div>
</code></pre></div>
<p>Como veis dentro de nuestro método <strong>render</strong> le hemos añadido <strong>bind(this)</strong>, es decir, enlazame el this de render con mi método getName et voilá:</p>
<p><img srcset="/assets/images/2017/08/Screen-Shot-2017-08-02-at-08.41.36.png" alt="React Superhero (I): Cambios en un mismo componente"><br>
Realmente es todo muy sencillo ¿verdad?<br>
Antes de terminar con este post me faltaría comentar otro concepto, fijaros en esta parte del código que casi no hemos comentado:</br></br></img></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">this.setState(this.name = {nombre: input.target.value});
</code></pre></div>
<p>Hemos hablado de la propiedad <strong>setState</strong> pero no mucho de lo que hay dentro, si miráis un poco el código esto es prácticamente lo mismo que tenemos dentro de nuestro método constructor(es un poco feo no?). Pues bien realmente la propiedad tiene un motivo por el que se llama <strong>setState()</strong> y es porque el método <strong>constructor</strong> ya está preparado para gestionar <strong>los cambios de estado</strong>, si cambiamos el nombre de la propiedad y en lugar de <strong>name</strong> ponemos <strong>state</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">constructor(){
super();
this.state = {
nombre: "Your Super Name"
}
}
</code></pre></div>
<p>Veamos como tendría que quedar nuestro método <strong>getName</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">getName(input){
this.setState({nombre: input.target.value});
}
</code></pre></div>
<p>Y que no se nos olvide cambiar nuestro placeholder:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><input onChange={this.getName.bind(this)}></input>
<h4> { this.state.nombre } </h4>
</code></pre></div>
<p>Si lo probáis veréis que todo funciona correctamente y hemos quitado alguna cosa que no quedaba del todo bien, aún así puede que algún momento queramos usarlo por lo que solo tenemos que recordar que si en el constructor no lo hacemos todo dentro del <strong>this.state</strong>, a la hora de usarlo es necesario indicar la estructura completa del objeto o propiedad que queremos cambiar.<br>
En el próximo post veremos como comunicarnos entre componentes y alguna cosa más. Nos vemooooooos</br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[React Superhero : Introducción]]></title><description><![CDATA[Empiezo nueva sección en el blog (tenía muchísimas ganas de empezar con React).
Os cuento un poco que es esto:
* Esta desarrollado por Facebook que aunque no lo parezca nos da algo de
confianza en cuanto a su durabilidad a la larga y su estabilidad.
* Se centra mucho en la parte de UI, es decir seria la V del MVC.
* Es muy útil para construir grandes aplicaciones que cambian con el tiempo.
* Gracias a su Virtual DOM el rendimiento no se ve severamente afectado cuando
la información n]]></description><link>https://jlgarcia.fulldev.ninja/react-superhero-introduccion/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f1a</guid><category><![CDATA[reactjs]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Mon, 07 Aug 2017 15:33:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/ea41313c22f611d45d277d453c4273d1/Captain-Atom.jpg" alt="React Superhero : Introducción"/><p>Empiezo nueva sección en el blog (tenía muchísimas ganas de empezar con React).</p>
<p>Os cuento un poco que es esto:</p>
<ul>
<li>Esta desarrollado por Facebook que aunque no lo parezca nos da algo de confianza en cuanto a su durabilidad a la larga y su estabilidad.</li>
<li>Se centra mucho en la parte de UI, es decir seria la V del MVC.</li>
<li>Es muy útil para construir grandes aplicaciones que cambian con el tiempo.</li>
<li>Gracias a su <strong>Virtual DOM</strong> el rendimiento no se ve severamente afectado cuando la información necesita actualizarse.</li>
<li>Se basa en componentes, haciéndolos reutilizables fácilmente.</li>
<li>Lo podemos integrar a cualquier API.</li>
<li>Y es JavaScript :)</li>
<li>Se puede integrar con Node, Ruby o cualquier otro lenguaje de backend.</li>
<li>Tiene framework para mobile (<strong>React Native</strong>, que lo venden como 'nativo'), que será lo siguiente que veremos cuando terminemos con el básico ;)</li>
<li>Usa <strong>JSX</strong> que es una especie de lenguaje tipo XML para crear nuestros componentes. Básicamente nos permite usar código HTML en variables de JS. Tenéis mas información sobre esto en la pagina oficial de <a href="https://facebook.github.io/react/docs/introducing-jsx.html">React</a>.</li>
</ul>
<p>Suena bien no?? A mi me encanta:<br>
<img srcset="/assets/images/2017/08/1839631-catom_cv1-1.jpg" alt="React Superhero : Introducción"/></br></p>
<p>Para trabajar con React necesitamos agregar mínimo 3 librerías a nuestro proyecto, es decir a nuestro index.html</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><!-- Libreria para trabajar con React -->
<script src="https://unpkg.com/react@latest/dist/react.js"></script>
<!-- Libreria de react para trabajar con el Dom-->
<script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
<!--Preprocesador para traducir lo que escribimos a todos los navegadores ya que react funciona con ECS6 y puede que no funcione en todos -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</code></pre></div>
<p>Bien con esto ya tenemos lo básico para trabajar con React. Como extra yo me descargado un plugin para <strong>Visual Studio Code</strong> para que reconozca el trabajo con babel en su momento. No es en absoluto necesario.</p>
<p>Pues bien antes de continuar hagamos una prueba para comprobar que todo funciona bien, si alguno ha trabajado o conoce un poco Angular vera como ciertos conceptos con parecidos.</p>
<p>Vamos a añadir una cabecera a nuestro fichero HTML usando React, para ello incluimos lo siguiente:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><script type="text/babel">
ReactDOM.render(
<h2>Hello with React</h2>,
document.getElementById('root');
);
</script>
</code></pre></div>
<p>Como vemos usamos en lugar de nuestro <strong>text/javascript</strong> típico, hemos puesto <strong>babel</strong> para que reconozca que tiene que usar babel. Y a continuación le indicamos que renderice en nuestro DOM el HTML que le pasamos, pero......¿donde? bien aquí es donde viene un concepto similar a angular. En Angular 1.5 por ejemplo teníamos nuestro ng-app:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><body ng-app="appName">
</code></pre></div>
<p>Donde le indicabamos donde empezaba a funcionar nuestra WebAPP, pues con React el concepto es parecido, si veis en el código superior hemos puesto que busque un elemento con el ID <strong>root</strong>(que podria ser cualquier otro nombre), que sera donde renderice el código, por lo que en algún sitio de nuestro código html tenemos que añadirlo jejejejje</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><div id="root"></div>
</code></pre></div>
<p>Bien y si todo ha ido bien tendríamos que tener algo similar a esto:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-29-at-14.23.56.png" alt="React Superhero : Introducción"><br>
Perfecto, como prueba de concepto esta bien, pero realmente así no se trabaja con React, es un lenguaje basado en componentes por lo que vamos a empezar por crear nuestro primer componente.</br></img></br></p>
<h2 id="primercomponente">Primer Componente</h2>
<p>Nuestro primer componente solo para ver de una forma rápida y facil como se harían, lo crearemos en el mismo index.html, dentro de nuestra etiqueta <strong>script</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><script type="text/babel">
class Supercomponente extends React.Component{
render(){
return <h2>Hello with React</h2>;
}
}
</code></pre></div>
<p>Como veis hemos creado una clase <strong>Principal (Ojo el nombre tiene que empezar en mayúsculas mas abajo veremos porque, y normalmente usamos inglés para los nombres, solo he puesto ese superNombre para que quede claro)</strong>, la cual extiende de <strong>React.Component</strong>. Luego simplemente creamos un método <strong>render</strong> que devuelve el mismo código que teníamos antes, pero... y como lo llamamos, bien aqui viene el porque de las <strong>mayúsculas</strong> al crear el componente.<br>
Los componentes pasan a ser etiquetas al estilo HTML y las ponemos en mayúsculas para diferenciarlas de las etiquetas normales, quedando la llamada al componente de esta manera:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">ReactDOM.render(
<SuperComponente/>,
document.getElementById('root')
);
</code></pre></div>
<p>Ponemos la etiqueta (importante cerrándola al final), y con esto debería funcionarnos igual que antes, y ya habríamos creado y usado nuestro primer componente.</p>
<p>Fácil verdad? Bien como importante recordar que un componente siempre tiene que tener un método <strong>render</strong> y que en las llamadas del ReactDOM, solo repito <strong>solo</strong> podemos pasarle un componente. Y ahora viene cuando nos deberíamos preguntar, ¿Y como hago para usar varios componentes unos con otros?¿No me digas que tenemos que hacer para todos un <strong>ReactDOM.render</strong>?......Pues no, no es necesario, realmente podemos integrar unos componentes con otros, pero a nivel de componentes, es decir, un componente puede tener y devolver otros componentes, vamos a crear otro componente y hagamos la prueba</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class MiSegundoComponente extends React.Component{
render(){
return <h2>REACT is in the HOUSE...YEAH!!!!</h2>
}
}
</code></pre></div>
<p>Ya tenemos otro componente y para llamarlo, lo hacemos desde el primero como si de otra etiqueta HTML normal se tratara, algo así no?:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class SuperComponente extends React.Component{
render(){
return (
<h2>Hello with React</h2>
<MiSegundoComponente/>
);
}
}
</code></pre></div>
<p>Fijaros que en el return he metido el contenido entre <strong>()</strong>, pero hagamos la prueba.....upssss no carga nada y si abrimos la consola del navegador vemos lo siguiente:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-29-at-19.08.39.png" alt="React Superhero : Introducción"><br>
Bien he puesto este error a propósito para que lo tengamos en cuenta como importante, <strong>TODOS LOS COMPONENTES ES NECESARIO QUE ESTEN DENTRO DE UNA ETIQUETA PADRE</strong>, es decir tienen que ser elementos HTML por si solos. En este caso seria simplemente meterlo todo dentro de un <strong>div</strong>:</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">class SuperComponente extends React.Component{
render(){
return (
<div>
<h2>Hello with React</h2>
<MiSegundoComponente/>
</div>
);
}
}
</code></pre></div>
<p>Y ahora ya si nos funcionaria:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-29-at-19.13.47.png" alt="React Superhero : Introducción"/></br></p>
<p>Como véis el uso de React es bastante fácil solo tenemos que tener unas pequeñas cosas en cuenta, como por ejemplo que los componentes tengan que estar encapsulados dentro de una etiqueta principal para que funcionen.</p>
<p>Y hasta aquí este post introductorio de React, os animo a seguir los siguientes si queréis aprender al mismo tiempo que yo a usar React, nos vemos en el siguiente.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Go Go Power Ra....ah que no: Go Parte 5 - Maps]]></title><description><![CDATA[Espero que este post sea bastante rápido jejejejej.
En este caso hablaremos de los Maps o lo que en otros lenguajes conoceríamos
como diccionario. En general siguen las mismas teorías que los arrays o los
slices en cuanto a creación y a lo referente al rendimiento, los mapas crecen
dinámicamente pero podemos indicarles el tamaño lo que optimizaría un poco su
rendimiento.
Creación
Empecemos con la creación. Como ya hemos visto en Go tenemos siempre varias
formas de crear los elementos:
* Form]]></description><link>https://jlgarcia.fulldev.ninja/go-go-power-ra-ah-que-no-go-parte-5-maps/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f16</guid><category><![CDATA[Go]]></category><category><![CDATA[Golang]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Sun, 23 Jul 2017 08:57:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-2.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-2.png" alt="Go Go Power Ra....ah que no: Go Parte 5 - Maps"/><p>Espero que este post sea bastante rápido jejejejej.<br>
En este caso hablaremos de los <strong>Maps</strong> o lo que en otros lenguajes conoceríamos como diccionario. En general siguen las mismas teorías que los <strong>arrays</strong> o los <strong>slices</strong> en cuanto a creación y a lo referente al rendimiento, los mapas crecen dinámicamente pero podemos indicarles el tamaño lo que optimizaría un poco su rendimiento.</br></p>
<h1 id="creacin">Creación</h1>
<p>Empecemos con la creación. Como ya hemos visto en Go tenemos siempre varias formas de crear los elementos:</p>
<ul>
<li>Forma básica</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//var nombreVariable map[tipoClave]tipoValor
var rangerRojo map[string]int
</code></pre></div>
<ul>
<li>Declaración corta:</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Inicializando sin valores
rangerRojo := map[string]int{}
//Inicializando con valores. Obligatoria la coma ultima
rangerVerde := map[string]int{
"Fuerza": 10000,
"Resistencia": 5000,
}
</code></pre></div>
<ul>
<li>Usando <strong>make</strong></li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangerVerde := make(map[string]int)
//Al igual que en los arrays podemos indicar el tamaño para optimizar rendimiento.
rangerNegro := make(map[string]int, 2)
</code></pre></div>
<h1 id="usandomap">Usando Map</h1>
<p>Ya hemos visto un poco como es la creación de <strong>Maps</strong> en golang, no es muy complicado no?, veamos ahora algunos detalles de su uso.</p>
<p>Cuando asignamos el valor, realmente este devuelve 2, el contenido que queremos sacar y si existe o no. Veamoslo con un ejemplo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangerRojo := map[string]int{
"Fuerza": 10000,
}
rangerVerde := make(map[string]int)
power, exist := rangerRojo["Fuerza"]
fmt.Println("Valor: ", power, "Existe: ", exist)
power2, exist2 := rangerVerde["Fuerza"]
fmt.Println("Valor: ", power2, "Existe: ", exist2)
</code></pre></div>
<p>He usado dos formas de crear maps y el resultado de esto seria:</p>
<p><img srcset="/assets/images/2017/07/Screen-Shot-2017-07-20-at-21.08.38.png" alt="Go Go Power Ra....ah que no: Go Parte 5 - Maps"><br>
Como veis nos inicializa el valor como suele hacer Go y nos indica que no existe realmente.</br></img></p>
<h2 id="borrandocontenidodeunmap">Borrando contenido de un Map</h2>
<p>En este caso Go se vuelve muy útil tiene una función propia para poder eliminar el elemento que queramos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">delete(rangerRojo,"Fuerza")
</code></pre></div>
<p>Probémoslo en un ejemplo más completo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangerRojo := map[string]int{
"Fuerza": 10000,
"Resistencia": 500,
}
fmt.Println(rangerRojo)
delete(rangerRojo, "Fuerza")
fmt.Println(rangerRojo)
</code></pre></div>
<p>Y como vemos elimina el contenido sin problemas:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-20-at-21.16.50.png" alt="Go Go Power Ra....ah que no: Go Parte 5 - Maps"/></br></p>
<h2 id="recorrerunmap">Recorrer un MAP</h2>
<p>Para recorrer un MAP usamos la misma teoría que para los <strong>arrays</strong> o <strong>slices</strong>: <strong>RANGE</strong> vamos directos al ejemplo ya que es bastante simple:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangerRojo := map[string]interface{}{
"Fuerza": 10000,
"Resistencia": 500,
"Inteligencia": "200",
"Arma": "Espada",
}
for key, value := range rangerRojo {
fmt.Println("Clave: ", key, " Valor: ", value)
}
</code></pre></div>
<p>Tenemos un <strong>map</strong> que tiene como <strong>claves</strong> varios strings representando las características de nuestro ranger y como <strong>valor</strong> he introducido algo que no habiamos visto todavia <strong>INTERFACE{}</strong>, bueno como resumen haceros a la idea de que es un tipo especial que funciona como un genérico, es decir, que representa cualquier valor(por eso podemos tener valores tipo <strong>INT</strong> y tipo <strong>STRING</strong>) y al recorrerlo tenemos esto:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-20-at-21.34.29.png" alt="Go Go Power Ra....ah que no: Go Parte 5 - Maps"><br>
<span style="color:red">OJO a tener en cuenta, no tiene porque hacerlo en orden sobretodo si introducimos algo a posteriori</span>, mirar un ejemplo:</br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangerRojo := map[string]interface{}{
"Fuerza": 10000,
"Resistencia": 500,
"Inteligencia": 150,
"Arma": "Espada",
}
rangerRojo["Maná"] = 150
for key, value := range rangerRojo {
fmt.Println("Clave: ", key, " Valor: ", value)
}
</code></pre></div>
<p>He añadido otra propiedad a nuestro ranger y el resultado es:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-20-at-21.39.11.png" alt="Go Go Power Ra....ah que no: Go Parte 5 - Maps"/></br></p>
<p>Si lo ejecuto de nuevo:</p>
<p><img srcset="/assets/images/2017/07/Screen-Shot-2017-07-20-at-21.40.10.png" alt="Go Go Power Ra....ah que no: Go Parte 5 - Maps"/></p>
<p>Por último y como he adelantado en el ejemplo anterior:</p>
<h2 id="aadirelementosanuestromap">Añadir elementos a nuestro MAP</h2>
<p>Bueno como ya hemos visto esto es muy sencillo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangerRojo["Maná"] = 150
fmt.Println(rangerRojo)
</code></pre></div>
<p>Y nos muestra<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-20-at-21.43.26.png" alt="Go Go Power Ra....ah que no: Go Parte 5 - Maps"><br>
Por el momento hemos terminado con los mapas, profundizaremos en el trabajo con ellos más adelante.<br>
Sin mucho más nos vemos en la siguiente superNinjas :)</br></br></img></br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Cloud Adventures: Android y Azure Active Directory Login]]></title><description><![CDATA[Estreno otra sección, en este caso estará centrado en problemas que me he ido
encontrado con los servicios Cloud a la hora de desarrollar alguna aplicación
nativa para Android o IOS.
En este caso le toca el turno a Azure, por ciertas necesidades he tenido que
"pegarme" con el servicio para que me funcionara el Login con el servicio de
Azure Active Directory.
Vuelve a ser por el problema de la documentación existente, que creo que es el
único problema con los servicios Cloud, que la documentación]]></description><link>https://jlgarcia.fulldev.ninja/cloud-adventures-android-y-azure-active-directory-login/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f13</guid><category><![CDATA[azure]]></category><category><![CDATA[cloud]]></category><category><![CDATA[android]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Wed, 19 Jul 2017 19:39:07 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/258a34bdac22a1c7f123fe43c9931f62/cloud-ninjaaz.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/258a34bdac22a1c7f123fe43c9931f62/cloud-ninjaaz.png" alt="Cloud Adventures: Android y Azure Active Directory Login"/><p>Estreno otra sección, en este caso estará centrado en problemas que me he ido encontrado con los servicios <strong>Cloud</strong> a la hora de desarrollar alguna aplicación nativa para Android o IOS.<br>
En este caso le toca el turno a Azure, por ciertas necesidades he tenido que "pegarme" con el servicio para que me funcionara el Login con el servicio de Azure Active Directory.<br>
Vuelve a ser por el problema de la documentación existente, que creo que es el único problema con los servicios Cloud, que la documentación o no esta clara o no esta actualizada.</br></br></p>
<p>Este escenario es muy simple, queremos hacer login, con una app Android, usando usuarios pertenecientes a Azure Active Directory, en un principio debería ser bastante fácil pero por lo menos en mi caso he tenido algún que otro problema.</p>
<p>Primero de todo:</p>
<h2 id="configurarelappserviceparaellogin">Configurar el AppService para el login</h2>
<p>Teóricamente bastante sencillo, vamos a la doc oficial:<br>
<a href="https://docs.microsoft.com/es-es/azure/app-service-mobile/app-service-mobile-how-to-configure-active-directory-authentication">Configure AAD in APPService</a></br></p>
<p>Y la seguimos, como tal hacemos todo y pensamos que todo esta bien, pero a la hora de probarlo falta alguna cosilla, que os voy adelantando por aqui:</p>
<p><img srcset="/assets/images/2017/07/Azure.png" alt="Cloud Adventures: Android y Azure Active Directory Login"/></p>
<p>Como véis en la foto en las redirecciones URL permitidas necesitamos añadirle algo similar a lo que veis en la foto, básicamente es el nombre de tu <strong>appservice</strong> seguido de un extra:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">appservicename://easyauth.callback
</code></pre></div>
<p>Esto es importante, lo que pongamos aqui lo tendremos que poner tambien en nuestra aplicación en algún momento, en el caso de Android, lo haremos en el manifest.</p>
<p>Siguiente:</p>
<h2 id="encontrarelsdk">Encontrar el SDK</h2>
<p>Bueno esto realmente depende de que queramos hacer y de como tengamos montado el entorno en Azure, en mi caso he creado un Mobile AppService, por lo que en condiciones normales deberíamos trabajar con el SDK para ello.</p>
<p>Bien pues en este caso deberia ser bastante fácil, la documentación oficial esta bastante bien para esto:<br>
<a href="https://docs.microsoft.com/es-es/azure/app-service-mobile/app-service-mobile-android-how-to-use-client-library">Azure SDK Android</a></br></p>
<p>Como veis al inicio te lo dice, básicamente usa el compile pertinente y un par de cosas más y listo.</p>
<p>Y por último:</p>
<h2 id="cdigonecesarioparaellogin">Código necesario para el login</h2>
<p>Bien seguramente si habeis mirado los links que he puesto más arriba habréis visto que casi todo el código que necesitamos ya estaba, concretamente en este <a href="https://docs.microsoft.com/es-es/azure/app-service-mobile/app-service-mobile-android-how-to-use-client-library">Azure SDK Android</a></p>
<p>Creamos una conexión de cliente en el onCreate:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">MobileServiceClient mClient = new MobileServiceClient(
"<MobileAppUrl>", // Replace with the Site URL
this); // Your application Context
</code></pre></div>
<p>Por si no lo tenéis claro <strong>MobileAppUrl</strong> es la url de vuestro APPService algo similar a:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">https://nombreDeApp.azurewebsites.net
</code></pre></div>
<p>El resto es como viene en la documentación, pero en nuestro caso como <strong>provider</strong> de login de backend ponemos <strong>aad</strong> o podemos usar:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory
</code></pre></div>
<p><span style="color:red">Un par de detalles muy importantes</span>:</p>
<ul>
<li>siempre que en la documentación pone algo de <strong>url_scheme</strong> se refiere a la url de nuestra app o al menos al nombre.</li>
<li>Tenemos que tener esto en el <strong>manifest.xml</strong> (con la URL de nuestra app)</li>
</ul>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"><activity android:name="com.microsoft.windowsazure.mobileservices.authentication.RedirectUrlActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="nombreDeApp" android:host="easyauth.callback"/>
</intent-filter>
</activity>
</code></pre></div>
<p><strong>OJO con ese easyauth.callback</strong> es el que permitimos más arriba en las redirecciones y sin el nada funciona.</p>
<p>Como tal solo he remarcado las partes que me han parecido más importantes, la gran mayoria de las cosas funcionan bien siguiendo la información que aparece en los links que os he comentado más arriba.</p>
<p>En otro post comentare como obtener datos del usuario que ha realizado el login, ya que a simple vista no es muy intuitivo, hasta la próximaaaaaa.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Go Go Power Ra....ah que no: Go Parte 4 - Arrays y Slices II]]></title><description><![CDATA[En este post vamos a ir viendo como se podrian hacer las cosas mas habituales
con los Arrays o Slices, como puede ser recorrerlos, veremos tambien como
podemos pasar de uno a otro para la optimización, sin mucho mas empezamos.
Recorrer un array o slice
Empecemos por el caso más habitual y es la necesidad de recorrer el contenido de
un array, en este punto voy a adelantar alguna otra cosa que no es solo de Array
o Slices, pero creo que es mejor verlo en esta parte.
Para recorrer un array, tipic]]></description><link>https://jlgarcia.fulldev.ninja/go-parte-4-arrays-y-slices-ii/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f12</guid><category><![CDATA[Go]]></category><category><![CDATA[Golang]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 18 Jul 2017 19:19:48 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-3.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-3.png" alt="Go Go Power Ra....ah que no: Go Parte 4 - Arrays y Slices II"/><p>En este post vamos a ir viendo como se podrian hacer las cosas mas habituales con los Arrays o Slices, como puede ser recorrerlos, veremos tambien como podemos pasar de uno a otro para la optimización, sin mucho mas empezamos.</p>
<h2 id="recorrerunarrayoslice">Recorrer un array o slice</h2>
<p>Empecemos por el caso más habitual y es la necesidad de recorrer el contenido de un array, en este punto voy a adelantar alguna otra cosa que no es solo de Array o Slices, pero creo que es mejor verlo en esta parte.</p>
<p>Para recorrer un array, tipicamente lo hacemos un bucle <strong>for</strong>, pues en este caso Go tiene un proceso muy similar específico (aunque se podria simular un for normal, haciendo el código a mano pero me parece innecesario, con el código lo vereis mejor)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers := []string{"Ranger Rosa", "Ranger Amarillo"}
for index, ranger := range rangers {
fmt.Println("El indice o posicion es: ", index)
fmt.Println("El Ranger de esa posicion es:", ranger)
}
</code></pre></div>
<p>Con un resultado similar a este:<br>
<img srcset="/assets/images/2017/07/Screen08.49.53.png" alt="Go Go Power Ra....ah que no: Go Parte 4 - Arrays y Slices II"><br>
Como vemos aqui tenemos un par de palabras reservadas que no habiamos usado: <strong>for</strong> y <strong>range</strong>, mas o menos os podéis imaginar la funcion que tiene cada una, básicamente esto quiere decir "Por cada índice y ranger dentro del rango de rangers....."</br></img></br></p>
<p>Bastante sencillo no?? Si os fijais tenemos la declaración corta de variables <strong>:=</strong>, lo que esta haciendo es asignar en cada vuelta, el índice y el valor en los nombres de variables que hemos puesto(podrian ser otros perfectamente).</p>
<p>Y si no queremos el índice?? Básicamente ignoramos el resultado:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">for _, ranger := range rangers {
fmt.Println("El Ranger de esa posicion es:", ranger)
}
</code></pre></div>
<p>El <strong>_</strong> en Go es un valor especial(funciona igual que en Swift por ejemplo) con el que estamos indicando que ignore ese resultado que podemos obtener de una función o cualquier otro proceso como puede ser este que acabamos de ver de recorrer un array.</p>
<h2 id="separandounarray">Separando un array</h2>
<p>O mas bien crear un subarray con parte del array original, es decir, veamos como partir un array para extrar el rango de posiciones que nos interese.<br>
En go tenemos la posibilidad de seleccionar un rango de X posiciones dentro de un array, de una manera bastante sencilla:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">miniRangers := rangers[:2]
fmt.Println("Hemos seleccionado del inicio a la posicion 2 sin incluirla:")
fmt.Println(miniRangers)
miniRangers2 := rangers[2:4]
fmt.Println("Hemos seleccionado desde la posicion 2 hasta la 4 sin incluirla:")
fmt.Println(miniRangers2)
miniRangers3 := rangers[4:]
fmt.Println("Hemos seleccionado desde la 4 hasta el final")
fmt.Println(miniRangers3)
</code></pre></div>
<p><img srcset="/assets/images/2017/07/Screen09.09.05.png" alt="Go Go Power Ra....ah que no: Go Parte 4 - Arrays y Slices II"/></p>
<p>Tambien es posible asignar al mismo array o resumiendo cortar el array:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers := []string{"Ranger Rosa", "Ranger Amarillo", "Ranger Rojo", "Ranger Verde", "Ranger Negro"}
rangers = rangers[2:4]
fmt.Println("Hemos seleccionado del inicio a la posicion 2 sin incluirla:")
fmt.Println(rangers)
</code></pre></div>
<p><img srcset="/assets/images/2017/07/Screen09.12.15.png" alt="Go Go Power Ra....ah que no: Go Parte 4 - Arrays y Slices II"/></p>
<h2 id="tamaoycapacidad">Tamaño y Capacidad</h2>
<p>Estos ya los hemos visto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">fmt.Println(len(rangers))//Para el tamaño
fmt.Println(len(rangers))//Capacidad
</code></pre></div>
<h2 id="aadir">Añadir</h2>
<p>Tambien hemos visto como añadir, ya sea en un <strong>array</strong> hasta su tamaño designado y en un <strong>slice</strong> cuando no esta inicializado:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var rangersDesignados [2]string
rangersDesignados = append(rangersDesignados,"R.Rojo","R.Verde")
rangersSlices = make([]string,2,10)
append(rangersSlices,"R.Rojo","R.Verde")
</code></pre></div>
<h2 id="eliminar">Eliminar</h2>
<p>Siento decir que aqui el lenguaje nos falla un poco, ya que no ofrece ningun método ya preparado para esto, como tal ya tenemos que jugar nosotros. En esta página:<a href="https://github.com/golang/go/wiki/SliceTricks">SliceTricks</a><br>
Tenemos alguna forma de hacer las operaciones mas comunes de eliminar, cortar, etc de manera eficiente.</br></p>
<h2 id="copiarspanstylecolorredimportantespan">Copiar<span style="color:red">(Importante)</span></h2>
<p>En un principio esto puede no parecer nada, estamos hablando de copiar un array o slice en otro......bueno pues no es tan simple, ¿recordáis lo que comentamos en el post anterior sobre tamaño y capacidad? Por refrescar rápidamente, el <strong>tamaño</strong> era la cantidad de elementos que tenia un slice o array y la <strong>capacidad</strong> la reserva de elementos que puede contener, es decir, la cantidad máxima de elementos que puede tener. Recordemos que Go lo que hace es reservar un espacio en memoria para almacenar una cantidad aproximada de datos, lo <span style="color:red">importante</span> venia a la hora de aumentar, como tal el <strong>slice</strong> comentamos que al aumentar lo que hacia era reservarse el doble de la capacidad que tenia anteriormente. Esto con slices pequeños esta muy bien, pero ¿y si tenemos un slice de 1000 elementos? En cuanto añadamos 1 más se reservara un espacio de 2000.</p>
<p>Pues bien con este escenario tenemos la accion de <span style="color:red">copiar</span> como solución, lo que hacemos es copiar un array en otro con la capacidad ajustada a lo que queramos, la forma de usarlo es simple:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">copy(destino, origen)
</code></pre></div>
<p>Bastante simple no? Pues veamos un ejemplo y apliquemos un poco de lógica para optimizar el consumo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Creamos dos slices
slice := []int{1, 2, 3, 4}
copia := make([]int, 4)
copy(copia, slice)
fmt.Println(slice)
fmt.Println(copia)
</code></pre></div>
<p>Como vemos hemos creado un slice con la forma corta, con contenido, y otro vacio con un tamaño y capacidad de 4. Si imprimimos el contenido todo estaría normal, pero un detalle a tener en cuenta es que realmente <strong>copy</strong> tiene en cuenta la capacidad del slice de destino (en este caso copia), como le hemos puesto una capacidad de 4, nos copia todo el contenido. Pongamos un ejemplo si ponemos menos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Si cambiaramos copia con otra longitud
copia2 := make([]int, 2)
copy(copia2, slice)
fmt.Println(slice)
fmt.Println(copia2)
//Veriamos como solo nos copia 2 elementos,
</code></pre></div>
<p>Lo mejor es controlar el tamaño(no la capacidad ojo), del slice origen y usar eso para crear el destino:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//para no equivocarnos lo ideal seria
copia3 := make([]int, len(slice))
copy(copia3, slice)
fmt.Println(slice)
fmt.Println(copia3)
//Con esto si cambia el tamaño del slice la copia tambien.
//Como buena practica, aunque segun el entorno, es añadir el doble del tamaño a la capacidad
copia4 := make([]int, len(slice), len(slice)*2) //O con la capacidad segun el caso
copy(copia4, slice)
fmt.Println(slice)
fmt.Println(copia4)
</code></pre></div>
<p>Bueno creo que por el momento vamos a dejar los <strong>arrays</strong> y <strong>slices</strong> para continuar con otras cosas, recordar mirar el link <a href="https://github.com/golang/go/wiki/SliceTricks">SliceTricks</a> y en otro de mis post tengo algo mas de trabajo con arrays: <a href="/go-tricks-i-array-contains/">Go Tricks I</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Go Tricks (I): Array contains]]></title><description><![CDATA[Comienzo sección nueva, en este caso son pequeños post que trataran sobre algún
truco para trabajar con Go, como todo existen varias formas de hacer, estas
serán solo algunas posibles no siempre serán las mejores pero seguro que
funcionan ;)
En este primer post vamos a ver como comprobar si un elemento existe dentro de
un array(o slice), lo veremos con strings pero puede ser con cualquier
tipo(primitivo por lo menos)
Como sabemos no tenemos forma directa en Go de comprobar si algo existe dentr]]></description><link>https://jlgarcia.fulldev.ninja/go-tricks-i-array-contains/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f14</guid><category><![CDATA[Go]]></category><category><![CDATA[Golang]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Thu, 13 Jul 2017 09:00:34 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-2.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-2.png" alt="Go Tricks (I): Array contains"/><p>Comienzo sección nueva, en este caso son pequeños post que trataran sobre algún truco para trabajar con Go, como todo existen varias formas de hacer, estas serán solo algunas posibles no siempre serán las mejores pero seguro que funcionan ;)</p>
<p>En este primer post vamos a ver como comprobar si un elemento existe dentro de un <strong>array(o slice)</strong>, lo veremos con strings pero puede ser con cualquier tipo(primitivo por lo menos)</p>
<p>Como sabemos no tenemos forma directa en Go de comprobar si algo existe dentro de un array por lo que debemos implementarlo nosotros.<br>
Una forma de hacerlo es la habitual de recorrer el array e ir comprobando pero realmente tenemos un par de formas(mínimo) más que yo creo que pueden ser más eficientes, aunque siempre depende del caso concreto.</br></p>
<h3 id="primera">Primera:</h3>
<p>Veamos una típica recorriendo el array</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">list := []string{"a", "z", "j", "f", "i", "v", "r", "c", "l", "p", "h", "w", "k", "e", "u", "s", "b"}
for _, v := range list {
if v == "b" {
fmt.Println("Existe")
break
}
}
</code></pre></div>
<p>Método bastante sencillo, recorremos el array y comprobamos si es lo que buscamos, en cuanto lo encuetre salimos del for. Es bastante rápido la verdad.</p>
<h3 id="segunda">Segunda:</h3>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">list := []string{"a", "x", "z", "j", "f", "i", "v", "r", "c", "l", "p", "h", "w", "k", "e", "u", "s", "b"}
set := make(map[string]bool)
for _, v := range list {
set[v] = true
}
fmt.Println(set["b"])
</code></pre></div>
<p>Tenemos una array de strings desordenado, lo que hacemos es crear un <strong>map</strong>(lo que seria un diccionario en otros lenguajes), de clave=valor donde la clave es el contenido del array, y como valor le he puesto true, para que cuando comprobemos que existe muestre un <strong>true</strong>(aunque eso pasaria con todos), es un poquito de azuquitar visual que hemos puesto. Realmente nos pasaria lo mismo si intentamos asignar el valor de forma corta, como tal recordar que los maps al asignarlos a otra variable nueva devuelven realmente 2 valores, el contenido del map y si existe o no.</p>
<p>Como veis bastante sencillo, tenemos un for si o si pero es bastante rápido. Fijaos que le he puesto el último valor con la idea de que al final haremos pruebas de cuanto tarda cada uno.</p>
<h3 id="tercera">Tercera:</h3>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">list := []string{"a", "x", "z", "j", "f", "i", "v", "r", "c", "l", "p", "h", "w", "k", "e", "u", "s", "b"}
sort.Strings(list)
i := sort.SearchStrings(list, "b")
fmt.Println(list[i] == "b")
</code></pre></div>
<p>Lo primero que hacemos es ordenar el array y luego nos valemos del método <strong>SearchStrings</strong>(tiene search de todo) que tiene el objeto sort, le pasamos el array y lo que queremos buscar y nos devuelve la posición en la que se encuentra. A continuación comprobamos si el array tiene en la posición recibida el string que buscamos y voilá.<br>
<strong>OJO!! Hacemos la comprobación de list[i] == "b" porque el método SearchStrings devuelve la posición donde deberiamos insertar el elemento en el caso de que no exista para que este ordenado directamente al añadirlo</strong></br></p>
<p>Esta forma a mi me gusta más pero en grandes cantidades de datos realmente tendriamos que probar su eficienca</p>
<h2 id="pruebasversus">Pruebas VERSUS</h2>
<p>Vamos a ver la diferencia de lo que tarda cada uno, esto no es del todo válido ya que depende de muchos factores pero es solo por ver lo que podria ser un acercamiento.<br>
Vamos a crear un bucle rápido con cada tipo, que nos muestre el tiempo que ha tardado, pondremos unas 50 ejecuciones de cada uno para ver un poco la media, pero siempre tener en cuenta que afecta la cantidad de código que tengamos un simple <strong>Print</strong> puede alterar los valores:</br></p>
<h3 id="primermtodo">Primer método</h3>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">j := 0
for {
t1 := time.Now()
list := []string{"a", "z", "j", "f", "i", "v", "r", "c",
"l", "p", "h", "w", "k", "e", "u", "s", "b"}
for _, v := range list {
if v == "b" {
//Aqui podriamos hacer que muestre true o algo asi
break
}
}
fmt.Println("Tiempo total: ", time.Since(t1))
if j == 50 {
break
}
j++
</code></pre></div>
<p>Seguiremos la misma linea para los 3, creamos una especie de bucle while en el que cuando sea 50 la variable <strong>j</strong> se salga de la funcion.<br>
Esta nos daria algo parecido a esto:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-13-at-09.07.51.png" alt="Go Tricks (I): Array contains"><br>
La primera ejecución tarda un poco mas y luego se mantiene, muy rápido no??(el array es muy pequeño jejejejje)</br></img></br></br></p>
<h3 id="segundomtodo">Segundo método:</h3>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">j := 0
for {
t1 := time.Now()
list := []string{"a", "z", "j", "f", "i", "v", "r", "c", "l", "p", "h", "w", "k", "e", "u", "s", "b"}
set := make(map[string]bool)
for _, v := range list {
set[v] = true
}
_ = set["b"]
fmt.Println("Tiempo total: ", time.Since(t1))
if j == 50 {
break
}
j++
</code></pre></div>
<p>Nos da unos tiempos de este estilo<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-13-at-09.12.25.png" alt="Go Tricks (I): Array contains"><br>
Bien aqui vemos que hemos bastante mas lentos en comparación, le he puesto el <strong>_ = set["b"]</strong> para simular que haciamos algo para comprobar.<br>
Este método tiene una ventaja, y es que si queremos buscar algo más ya lo tenemos en el <strong>map</strong> set. Como desventaja es que posiblemente consumamos recursos innecesariamente.</br></br></img></br></p>
<h3 id="tercermtodo">Tercer Método:</h3>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">j := 0
for {
t1 := time.Now()
list := []string{"a", "z", "j", "f", "i", "v", "r", "c", "l", "p", "h", "w", "k", "e", "u", "s", "b"}
sort.Strings(list)
i := sort.SearchStrings(list, "b")
_ = (list[i] == "b")
fmt.Println("Tiempo total: ", time.Since(t1))
if j == 50 {
break
}
j++
</code></pre></div>
<p>Y con este ultimo obtenemos:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-13-at-09.18.12.png" alt="Go Tricks (I): Array contains"><br>
Vemos que es más rápido que el segundo pero menos que el primero. Como tal con este método si tenemos que realizar otra búsqueda como ya estaria ordenado seria más rápida, he probado y salen unos tiempos como estos:<br>
<img srcset="/assets/images/2017/07/Screen-Shot-2017-07-13-at-09.20.45.png" alt="Go Tricks (I): Array contains"><br>
Como veis llegamos a los nanosegundos, que no esta mal.</br></img></br></br></img></br></p>
<p>Al final todo esto es orientativo, siempre dependerá del entorno y la cantidad de elementos que tenga el array. Es bastante probable que la primera forma sea la más rápida en la mayoría de los entornos pero al final deberemos valorarlo en el momento. También es cierto que es más fácil crearnos un método de utilidad con la primera opción que con el resto, podríamos generalizar usando <strong>interface</strong> o cualquier cosa que se nos ocurra. Siendo esto bastante útil si pensamos en la concurrencia como Go funciona con copias de elementos(a no ser que usemos punteros) no tendríamos <em>"condiciones de carrera"</em>(race conditions) a la hora de acceder a los elementos.</p>
<p>Espero que os haya parecido interesante, nos vemos en el siguiente NINJA POST :)</p>
<p>P.D: Para el que no sepa lo que es el race condition, básicamente es la posibilidad de que se este accediendo al mismo elemento y al mismo tiempo, lo que generaría varios problemas(cosa que en Go si trabajamos con copias no tendríamos)</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I]]></title><description><![CDATA[En Go tenemos dos tipos de arrays o arreglos:
* Los que llaman arrays, son arreglos con una cantidad definida de elementos,es
decir, tienen un tamaño fijo y no pueden crecer.
* Los llamados slices, que son los arreglos o arrays más comunes, en los cuales
podemos añadir los elementos que queramos.
Y porque tenemos dos tipos? Pues básicamente es por el consumo de recursos, los
arrays definidos, solo se reservan los recursos que necesitan, los slices o
llamemoslos arrays ]]></description><link>https://jlgarcia.fulldev.ninja/go-go-power-ra-ah-que-no-go-parte-3-arrays-y-slices-i/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f0c</guid><category><![CDATA[Go]]></category><category><![CDATA[Golang]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Tue, 11 Jul 2017 20:11:39 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-2.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-2.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"/><p>En Go tenemos dos tipos de <strong>arrays</strong> o <strong>arreglos</strong>:</p>
<ul>
<li>
<p>Los que llaman <strong>arrays</strong>, son arreglos con una cantidad definida de elementos,es decir, tienen un tamaño fijo y no pueden crecer.</p>
</li>
<li>
<p>Los llamados <strong>slices</strong>, que son los arreglos o arrays más comunes, en los cuales podemos añadir los elementos que queramos.</p>
</li>
</ul>
<p>Y porque tenemos dos tipos? Pues básicamente es por el consumo de recursos, los <strong>arrays definidos</strong>, solo se reservan los recursos que necesitan, los <strong>slices</strong> o llamemoslos <strong>arrays dinámicos</strong> tienen siempre reservado una cantidad mayor de recursos para poder crecer. Más abajo veremos como saber esta cantidad.</p>
<h2 id="arraysdefinidos">Arrays definidos</h2>
<p>La forma de declararlos es bastante sencilla:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//supongamos que son 3
var rangers [3]string
rangers[0] = "Ranger Rojo"
rangers[1] = "Ranger Negro"
rangers[2] = "Ranger Amarillo"
//El uso es como todos los arrays
fmt.Println(rangers)
fmt.Println(rangers[0])
fmt.Println(rangers[1])
fmt.Println(rangers[2])
</code></pre></div>
<p>Si ejecutamos esto:<br>
<img srcset="/assets/images/2017/07/Screen0814.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"/></br></p>
<p>Hasta aqui todo parece normal, vamos a intentar añadir alguno mas:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers[3] = "Ranger Verde"
</code></pre></div>
<p>Vemos como el propio visual studio nos avisa:<br>
<img srcset="/assets/images/2017/07/Screen0831.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"><br>
La única forma que tendriamos de ampliar ese array, o más bien de trabajar con los datos que contiene, es hacer una copia del array en otro con más cantidad de elementos posibles(o que fuera un <strong>slice</strong>).</br></img></br></p>
<p>Más abajo veremos como hacer eso, ya que es común para ambos tipos de array.</p>
<h2 id="slices">SLICES</h2>
<p>Continuemos con los <strong>slices</strong>, que serán posiblemente el tipo más usado, sobretodo al principio.<br>
Tenemos varias formas de crear <strong>slices</strong>, cada una tiene sus peculiaridades.<br>
La primera:</br></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var rangers []string
rangers[0] = "Ranger Rosa"
fmt.Println(rangers)
</code></pre></div>
<p>En un principio todo parece normal, el compilador no se queja tampoco, <em>cool</em>, pero vamos a ejecutarlo:<br>
<img srcset="/assets/images/2017/07/Screen08.45.05.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"><br>
Como veis tenemos un bonito <span style="color:red">Panic</span> (para el que no se lo imagine es como muestra los errores) pero ¿porque?</br></img></br></p>
<p>Go al inicializar los <strong>slices</strong> si lo hacemos de esa forma los inicializa por defecto <strong>"vacios"</strong> pero no entendamos vacios como cualquier otro elemento que podemos asignarle un valor directamente, si no lo inicializa con <strong>"ausencia de todo"</strong> incluso de tamaño.<br>
Pero esto no significa que no podamos usarlo, Go tiene un método <strong>append</strong> que nos permite añadir los elementos que necesitemos:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers = append(rangers, "Ranger Rosa", "Ranger Rojo")
fmt.Println(rangers)
</code></pre></div>
<p>Podriamos añadir todos los que queramos, y como vemos funciona perfectamente:<br>
<img srcset="/assets/images/2017/07/Screen08.57.07.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"/></br></p>
<p>Antes de continuar con la siguiente forma de inicializar <strong>slices</strong> vamos a hablar de <strong>"Tamaño"</strong> y <strong>"Capacidad"</strong></p>
<p>¿¿??</p>
<p>Si jejejeje, con los slices en aplicaciones complejas tendremos que tener en cuenta estas dos cosas, pensando en la optimización por supuesto.</p>
<ul>
<li>
<p><strong>Tamaño</strong>: Básicamente es el tamaño que tiene ocupado el slice, lo que en otros lenguajes consultaríamos con un <strong>array.length</strong></p>
</li>
<li>
<p><strong>Capacidad</strong>: Es la cantidad de recursos reservada para ese <strong>slice</strong>.</p>
</li>
</ul>
<p>Es decir si pensamos en los slices como cajas, tenemos que un slice con una capacidad de 5 son 5 cajas, de las cuales 2 estan cerradas con algo dentro(tamaño 2) y otras 3 estan abiertas a la espera de tener algo dentro, pero estan ocupando su espacio en el suelo ya.</p>
<p>Ahora veamos la segunda forma de crear un <strong>slice</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers := make([]string,10)
//Aqui tendriamos un slice con 10 de tamaño y 10 de capacidad
rangers := make([]string,5,10)
//Y aqui tendriamos un slice con 5 de tamaño y 10 de capacidad
</code></pre></div>
<p>Veamos un ejemplo de código para ilustrar un poco mejor esto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var rangers []string
fmt.Println("Sin inicializar, es decir tamaño 0")
fmt.Println(rangers)
rangers = append(rangers, "Ranger Rosa", "Ranger Rojo")
fmt.Println("Append al no inicializado")
fmt.Println(rangers)
rangers2 := make([]string, 10)
fmt.Println("Usando make para asignar tamaño y capacidad iguales")
fmt.Println(rangers2)
rangers3 := make([]string, 5, 10)
fmt.Println("Usando make para asignar tamaño y capacidad distintos")
fmt.Println(rangers3)
</code></pre></div>
<p>Si ejecutamos este código tendriamos un resultado como este:<br>
<img srcset="/assets/images/2017/07/Screen09.30.55.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"><br>
Si os fijais tenemos bastantes diferencias en cuanto a la inicialización por defecto de cada uno de los slices, el <strong>primero</strong> realmente tendria un valor similar a <strong>null</strong>, en el <strong>segundo</strong> hemos inicializado ese null con dos elementos, en el <strong>tercero</strong> se ha aplicado la inicialización por defecto de go de strings(es decir "") sobre 10 elementos, en el <strong>ultimo</strong> esa misma inicialización sobre 5.</br></img></br></p>
<p>Ahora ya podemos usar lo que llamariamos asignación directa:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers2[2] = "Ranger Verde"
rangers3[3] = "Ranger Negro"
fmt.Println(rangers2)
fmt.Println(rangers3)
</code></pre></div>
<p><img srcset="/assets/images/2017/07/Screen20.56.57.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"/></p>
<p>Bien hemos comprobado que podemos añadir ahora por lo menos dentro del "tamaño inicializado", si nos fijamos cada elemento tiene una posición definida dentro del slice. Veamos ahora lo que pasa si intentamos añadir en una ubicación por encima del <strong>tamaño</strong>(ojo no de la capacidad). Lo vamos a intentar on <strong>ranger3</strong> que tiene una capacidad de 10 y un tamaño de 5:<br>
<img srcset="/assets/images/2017/07/Screen21.00.34.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"/></br></p>
<p>Vemos como nos vuelve a dar el error de que nos hemos salido del rango permitido. Para añadir por encima de esto tenemos que usar el mismo método que antes con <strong>append</strong></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers3 = append(rangers3, "Ranger Rosa", "Ranger Rojo")
fmt.Println(rangers3)
</code></pre></div>
<p>Si ahora ejecutamos veremos como despues del espacio que teniamos antes ha añadido los dos rangers nuevos.<br>
<img srcset="/assets/images/2017/07/Screen21.06.25.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"><br>
<strong>OJO a lo de los espacios</strong> vamos a ver una ultima forma de inicializar <strong>Arrays</strong> y <strong>Slices</strong> y volveremos a este ejemplo para ver cosas sobre la <strong>capacidad</strong> y el <strong>tamaño</strong>.</br></img></br></p>
<p>Como última forma vamos a ver la inicialización directa de ambos casos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">//Array definido
rangers2 := [2]string{"Ranger Verde", "Ranger Blanco"}
//Slice
rangers3 := []string{"Ranger Rosa", "Ranger Amarillo"}
fmt.Println(rangers2)
fmt.Println(rangers3)
</code></pre></div>
<p>Como tal no notamos ninguna diferencia a la hora de mostrarlos:<br>
<img srcset="/assets/images/2017/07/Screen21.17.55.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"/></br></p>
<p><strong>Atención</strong> si hacemos esto:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers2 := [3]string{"Ranger Verde", "Ranger Blanco"}
</code></pre></div>
<p>Nos añade,en este caso un string(podria ser cualquier tipo que hubieramos indicado) vacio en el elemento faltante.</p>
<p>Bien ahora vamos a probar a añadir:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers2 := [2]string{"Ranger Verde", "Ranger Blanco"}
rangers3 := []string{"Ranger Rosa", "Ranger Amarillo"}
rangers2 = append(rangers2, "Ranger Negro")
rangers3 = append(rangers3, "Ranger Blanco")
</code></pre></div>
<p>Si vemos el <strong>array definido</strong> se queja:<br>
<img srcset="/assets/images/2017/07/Screen21.20.36.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"/></br></p>
<p>Como tal sigue restringiendo su ampliación, lo contrario que el <strong>slice</strong>.<br>
Ahora vamos a ver la diferencia real entre uno y otro.</br></p>
<h2 id="lenycap">Len y Cap</h2>
<p>Go tiene como casi todos los lenguajes una forma de comprobar la cantidad de elementos que tiene un array,normalmente suele tener que ver con <strong>length</strong>, pues Go no iba a ser menos tenemos nuestro len:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers3 := []string{"Ranger Rosa", "Ranger Amarillo"}
fmt.Println(len(rangers3))
</code></pre></div>
<p>Esto nos devuelve un 2, cosa normal no?? Pero como tal antes hemos hablado de la <strong>capacidad</strong> también, en este caso Go tiene también una forma de ver la capacidad que tenemos reservada(básicamente es reserva en memoria)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers3 := []string{"Ranger Rosa", "Ranger Amarillo"}
fmt.Println("Tamaño",len(rangers3))
fmt.Println("Capacidad",cap(rangers3))
</code></pre></div>
<p>Esto nos devolveria:<br>
<img srcset="/assets/images/2017/07/Screen21.31.12.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"/></br></p>
<p>Hasta aqui todo normal no?? Todo tiene sentido verdad?? Vale ahora vamos a añadirle algo para aumentarlo, recordemos que con <strong>capacidad 2</strong> no podemos usar asignación directa para los siguientes elementos como tal tenemos que usar <strong>append</strong>, vamos a usar <strong>append</strong> y veamos que nos devuelve ahora:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers3 := []string{"Ranger Rosa", "Ranger Amarillo"}
rangers3 = append(rangers3, "Ranger Blanco")
fmt.Println("Tamaño", len(rangers3))
fmt.Println("Capacidad", cap(rangers3))
</code></pre></div>
<p>Para nuestra sorpresa al ejecutar vemos esto:<br>
<img srcset="/assets/images/2017/07/Screen21.34.02.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"><br>
<strong>UPS!!!</strong> <em>y que ha pasaaaaaooooo!!!????</em>, es simple Go lo que hace es duplicar la capacidad anterior, por lo que si no tenemos en cuenta y tratamos con slices muy grandes, por ejemplo imaginemos un array de 100 elementos, si añadimos 1 mas para hacer 101 tendriamos una capacidad de 200 siendo realmente inecesario.<br>
Veamoslo con un ejemplo añadiendo al código anterior los 2 rangers restantes:</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">rangers3 := []string{"Ranger Rosa", "Ranger Amarillo"}
rangers3 = append(rangers3, "Ranger Blanco")
fmt.Println("Tamaño", len(rangers3))
fmt.Println("Capacidad", cap(rangers3))
rangers3 = append(rangers3, "Ranger Rojo", "Ranger Negro")
fmt.Println("Tamaño", len(rangers3))
fmt.Println("Capacidad", cap(rangers3))
</code></pre></div>
<p>Vemos que tenemos de repente una capacidad de 8:<br>
<img srcset="/assets/images/2017/07/Screen21.39.27.png" alt="Go Go Power Ra....ah que no: Go Parte 3 - Arrays y Slices I"/></br></p>
<p>Creo que con esto mas o menos queda clara la diferencia entre los arrays definidos y los slices, hablando de consumo de memoria y del propio uso de uno u otro, siempre sera recomendable tener arrays definidos, veremos más adelante alguna forma de pasar de uno a otro.</p>
<p>En el próximo post veremos tambien como trabajar con ambos, para recorrerlos, por ejemplo, y varias cosas mas.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)]]></title><description><![CDATA[Vamos a ir viendo como trabajar con el lenguaje, es decir, como usar variables,
arrays, slices, estructuras...etc. He pensado que es mejor hacer post mas
cortos, y asi público un poco más rápido, por lo que cada post realmente tratará
unicamente de un tema.Sin entretenerme más empecemos a trabajar.
Variables y Constantes
Para los que no lo sepan, una variable es un elemento de un tipo
específico(numeral, texto, etc) que usamos para gestionar y poder trabajar con
ellos. Después de este resumen e]]></description><link>https://jlgarcia.fulldev.ninja/go-go-power-ra-go-parte-2-el-lenguaje-variables-tipos-primitivos/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f0b</guid><category><![CDATA[Go]]></category><category><![CDATA[Golang]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Wed, 28 Jun 2017 08:00:00 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-1.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled-1.png" alt="Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)"/><p>Vamos a ir viendo como trabajar con el lenguaje, es decir, como usar variables, arrays, slices, estructuras...etc. He pensado que es mejor hacer post mas cortos, y asi público un poco más rápido, por lo que cada post realmente tratará unicamente de un tema.Sin entretenerme más empecemos a trabajar.</p>
<h3 id="variablesyconstantes">Variables y Constantes</h3>
<p>Para los que no lo sepan, una variable es un elemento de un tipo específico(numeral, texto, etc) que usamos para gestionar y poder trabajar con ellos. Después de este resumen extraño, comento con un poco más de tecnicismos, realmente una variable es una dirección de memoria que reservamos donde almacenamos el valor que contiene la variable. Esto es importante entenderlo, en lenguajes como Go sobretodo, porque el lenguaje usa <strong>punteros</strong> (los veremos más adelante, pero resumiendo es como un acceso directo a esa dirección de memoria)</p>
<p>Vamos a empezar con los tipos primitivos o básicos que tiene el lenguaje(como tal podemos crear nuestros propios tipos, pero eso ya lo veremos), aunque más que ver los tipos voy a hablar de como trabajar con ellos.<br>
Los tipos básicos en Go los tenéis o en la documentación oficial o más resumido en el <a href="https://tour.golang.org/basics/11">tour</a> oficial del lenguaje.</br></p>
<p>En Go las variables tienen un tipado estático, y ¿esto que quiere decir?, pues que a la hora de declararlas tenemos que indicar el tipo, el cual no cambia:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var power int
var rangerName string
</code></pre></div>
<p>Un detalle <span style="color:red">importante</span>, en Go no existe nil, null, undefined ni nada similar, siempre, siempre, siempre las variables son iniciadas, si no lo son por nosotros, el lenguaje automáticamente le pone 0 o "", según el caso. Si intentamos imprimir eso:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">package main
import "fmt"
func main() {
var power int
var rangerName string
fmt.Println("Power ranger red power: ", power)
fmt.Println("Power ranger red name: ", rangerName)
}
</code></pre></div>
<p><img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-27-a-las-19.45.02.png" alt="Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)"><br>
El int es 0 y el string esta vacio.</br></img></p>
<p>Es posible tambien declarar varias variables del mismo tipo en la misma linea</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var power,speed int
</code></pre></div>
<p>Las variables es posible iniciarlas una vez que son declaradas(tambien si hemos declarado varias en la misma linea)</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">var power, speed int = 100,70
</code></pre></div>
<p>Si imprimimos con:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text"> fmt.Println("Power ranger red power: ", power)
fmt.Println("Power ranger red speed: ", speed)
</code></pre></div>
<p><img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-27-a-las-19.53.07.png" alt="Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)"><br>
Como extra Go tiene otra forma bastante mas ágil de declarar variables e iniciarlas que infiere el tipo (un poco de azúcar sintáctico)</br></img></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">power := 100
speed := 70
#Tambien podemos declarar varias a la vez
stamina, swordsSkill := 50, 80
# Y es posible usar distintos tipos en la misma declaración
megazordSkill, rangerName := 1000,"Scott"
## Realmente tambien infiere el tipo si inicializamos al declarar una variable
var power = 100 seria igual que lo de arriba
</code></pre></div>
<p>Si os fijais en la ultima declaración tenemos un int y un string, pues si imprimimos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">fmt.Println("Power ranger red power: ", power)
fmt.Println("Power ranger red speed: ", speed)
fmt.Println("Power ranger red stamina: ", stamina)
fmt.Println("Power ranger red swordsSkill: ", swordsSkill)
fmt.Println("Power ranger red megazordSkill: ", megazordSkill)
fmt.Println("Power ranger red name: ", rangerName)
</code></pre></div>
<p><img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-27-a-las-20.04.20.png" alt="Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)"/></p>
<p>En cuanto a las <strong>constantes</strong> comentar que como gran parte de los lenguajes Go también las tiene, básicamente es cambiar la palabra <strong>var</strong> por <strong>const</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">const hello = "Hello World"
const hello string = "Hello World"
</code></pre></div>
<h3 id="trabajarcondistintostipos">Trabajar con distintos tipos</h3>
<p>Go no traduce entre tipos como otros lenguajes, por lo que tenemos que hacerlo nosotros, si probamos con este ejemplo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">jump := 60
gravityForce := 9.8
fmt.Println(v / p * 2)
</code></pre></div>
<p>Tendriamos este error:<br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-27-a-las-20.11.51.png" alt="Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)"/></br></p>
<p>Como el error indica tenemos que igualar los tipos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">fmt.Println(float64(jump) / gravityForce * 2)
</code></pre></div>
<p>Esto ya no daria error y funcionaría sin problemas. No voy a especificar como transformar los tipos de todas las variables porque eso en la documentación esta bien explicado, y tenéis ejemplos. Tambien tenemos funciones para transformar de String a int y viceversa(esto veremos algun ejemplo mas adelante pero insisto en la documentación viene bastante bien y es realmente sencillo).<br>
Para los que tenga bastante experiencia,comentar que es posible sobreescribir los métodos propios que transforman todo en String,es decir lo que usa fmt, y hacer lo que nosotros queramos(esto lo veremos mas adelante), es bastante útil cuando no podemos imprimir algunos datos o funciones directamente por algún motivo(por ejemplo con los <strong>struct</strong>)</br></p>
<h3 id="variablesprivadasypblicas">Variables Privadas y Públicas</h3>
<p>En Go existe el concepto de variables públicas y privadas, las privadas solo son visibles en el fichero donde estan.<br>
La diferencia está en la declaración, si las declaramos con la primera letra en mayúsculas o en minusculas:</br></p>
<ul>
<li>Minúsculas = Privada</li>
<li>Mayúsculas = Pública</li>
</ul>
<p>Veamos un ejemplo:</p>
<p>Creemos una estructura de ficheros similar a esta donde tengamos el root del proyecto como comentamos en el post anterior:<br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-27-a-las-20.40.34.png" alt="Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)"><br>
Como vemos tenemos un fichero <strong>main.go</strong> como hemos tenido siempre, una carpeta <strong>rangerModel</strong> y dentro de esta un fichero <strong>rangerModel.go</strong></br></img></br></p>
<p>En <strong>rangerModel.go</strong> ponemos lo siguiente:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">package rangerModel
var power int
var speed int
</code></pre></div>
<p>Como vemos he puesto el nombre del paquete donde esta alojado para diferenciarlo del main.<br>
En el <strong>main.go</strong>:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">package main
import (
"vuestroRootPath/rangerModel"
"fmt"
)
func main() {
power := rangerModel.power
fmt.Println("Power ranger red power:", power)
}
</code></pre></div>
<p>Si guardamos ambos, vemos como nos da un error al instanciar el <strong>power</strong> del <strong>rangerModel</strong>:<br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-27-a-las-20.46.31.png" alt="Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)"><br>
Como tal no tenemos acceso a la variable o propiedad <strong>power</strong> de <strong>rangerModel</strong>.<br>
Ahora vamos a cambiar el power por <strong>Power</strong> en el modelo, quedando de esta manera(de paso le ponemos un valor):</br></br></img></br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">package rangerModel
var Power = 100
var speed int
</code></pre></div>
<p>Y lo mismo en el <strong>main</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">func main() {
power := rangerModel.Power
fmt.Println("Power ranger red power:", power)
}
</code></pre></div>
<p>Ahora si imprimimos:<br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-27-a-las-20.50.04.png" alt="Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)"><br>
Es bastante sencillo como veis, comentar que no es recomendable hacer variables públicas(o exportar variables según el lenguaje de Go), por eso nos da esta recomendación al ponerlo en mayúsculas:<br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-27-a-las-20.54.51.png" alt="Go Go Power Ra....ah que no: Go Parte 2 - El Lenguaje (Variables-Tipos Primitivos)"/></br></br></img></br></p>
<p>Por el momento dejamos aquí las variables básicas, más adelante seguiremos trabajando con ellas.<br>
Nos vemos en el siguiente</br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion]]></title><description><![CDATA[Empiezo con una nueva sección, mi aventura con el lenguaje GO, el cual he
descubierto que me encanta, es un lenguaje muy bueno y sencillo para tratar con
temas de concurrencia y realmente hace un montón de cosas por si solo(como su
paquete net que hace la vida mas fácil en cuanto a servidor Web se refiere), lo
vamos a ir viendo poco a poco. Sin mucho más empecemos
Instalación
El lenguaje lo podemos escribir desde cualquier editor de texto pero es
necesario instalar el compilador y realizar algu]]></description><link>https://jlgarcia.fulldev.ninja/go-go-power-ra-ah-que-no-go-parte1-intro-y-preparacion/</link><guid isPermaLink="false">Ghost__Post__5a338158333e0f134c248f06</guid><category><![CDATA[Go]]></category><category><![CDATA[Golang]]></category><dc:creator><![CDATA[Juan Luis Garcia Aparicio]]></dc:creator><pubDate>Sat, 03 Jun 2017 09:45:14 GMT</pubDate><media:content url="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://jlgarcia.fulldev.ninja/static/4c2a69b59a578389653f7d3cb966f439/Untitled.png" alt="Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion"/><p>Empiezo con una nueva sección, mi aventura con el lenguaje GO, el cual he descubierto que me encanta, es un lenguaje muy bueno y sencillo para tratar con temas de concurrencia y realmente hace un montón de cosas por si solo(como su paquete net que hace la vida mas fácil en cuanto a servidor Web se refiere), lo vamos a ir viendo poco a poco. Sin mucho más empecemos</p>
<h2 id="instalacin">Instalación</h2>
<p>El lenguaje lo podemos escribir desde cualquier editor de texto pero es necesario instalar el compilador y realizar algunas configuraciones. Desde la propia página <a href="https://golang.org/dl/">Go Download</a> están los paquetes, y las instrucciones. También es posible instalarlo con <strong>Homebrew</strong> (si lo usamos).</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">brew install golang
</code></pre></div>
<p>Para la correcta instalación tenemos que tener en cuenta que es necesario configurar ciertas variables de entorno, teneis toda la información en:<br>
<a href="https://golang.org/doc/install">Instalación GO</a></br></p>
<p>Haceros a la idea de que la documentación de Go es bastante completa por lo que en general encontraremos todo lo que necesitemos aquí:<br>
<a href="https://golang.org/doc/">Documentación GO</a></br></p>
<p>Solo como aclaración tener en cuenta lo que comenta la documentación sobre los variables de entorno, si ejecutamos algún intalador (MAC/Windows) no deberíamos tener que hacer nada, si algo no funciona comprobar que existe en la variable de entorno $PATH la referencia a Go y que es correcta:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">Windows
c:\Go\bin
Mac
echo $PATH <- nos devuelve lo que tenemos ahora mismo en el path
Esto deberia devolvernos una cadena de texto muy larga que en algún punto deberia poner algo similar a esto
/usr/local/go/bin
</code></pre></div>
<p>Si lo hacemos en Linux o con cualquier source, lo mejor es extraer el contenido en las rutas recomendadas y configurar las variables de entorno como aparece en la documentación.</p>
<p>Si tenéis algún problema buscar en internet que hay mucha información sobre esto, aun así si continuáis con problemas ponerlo en los comentarios e intentamos resolverlo.</p>
<p>Antes de continuar un detalle de algunas carpetas del directorio de Go, por si quereis buscar algo:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">bin <- binarios, los que instalamos con go install
package o pkg <- Trabajar con los wrappers dentro de nuestro código. Encapsuladores de C.
src <- Todo nuestro código fuente y la librerías de terceros. Las puede descargar go al realizar los imports en nuestras clases, o las podemos poner nosotros. Aqui es donde suele buscar el origen de los imports.
</code></pre></div>
<h2 id="algunosdetallessobrego">Algunos detalles sobre GO</h2>
<p>Go es un lenguaje <strong>compilado</strong> no interpretado, es decir, el código es compilado (transformado) a lenguaje máquina con lo que se genera un ejecutable que funcionará sin necesidad de nada más para la arquitectura para la que fue creado. Si hablamos de los errores, en este tipo de lenguajes deberíamos verlos en el proceso de compilación, pero veremos como con GO podemos probar nuestro código sin necesidad de compilar.</p>
<p>Un lenguaje interpretado es aquel en el que un tercero(normalmente llamado intérprete) lee nuestro código y lo traduce a código máquina, esto sucede cada vez que lo ejecutamos, y los errores los detectamos en este tiempo de ejecución.</p>
<p>Go es un lenguaje que se usa mucho para scripting en backend ya que es bastante rápido en ejecutar, sus librerías básicas cubren mogollón de escenarios y como he comentado el mismo script lo podriamos compilar para todos los S.O, aunque esto depende un poco de lo que haga jejejeje, no es tan mágico como suena. Personalmente me encanta por la parte de concurrencia y la parte de Web Server, que si mezclamos ambas cosas podemos hacer cosas muy curiosas y que consuman pocos recursos.<br>
Como ejemplo pongo un caso de uso de la empresa <a href="https://es.malwarebytes.com/">Malwarebytes</a> en el que gestionan <strong>1 Millón</strong> que bajaron sus consumos en un porcentaje muy alto usando GO <a href="http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/">link</a>. No se a vosotros pero a mi me parece muy interesante poder hacer cosas como esa.</br></p>
<p>Es un lenguaje con tipado estático, esto quiere decir que desde el principio al declarar las variables tenemos que indicarle el tipo que son. Aunque es cierto que GO tiene una forma de declaración y asignación de variables, en la que el lenguaje hace lo que se conoce como "inferencia de tipos", o lo que es lo mismo, el propio lenguaje define el tipo de la variable según el valor asignado(veremos mas adelante ambas formas)</p>
<p>Por último comentar que es un lenguaje que tiene características similares a C (como puede ser que usa punteros), compila directamente en ensamblador y un extra que es muy útil y que nos ahorra quebraderos de cabeza es que tiene <strong>recolector de basura</strong> es decir, no tenemos que controlar el estado de las variables o funciones para saber si se estan usando o no, ya lo hace Go por nosotros y aunque afecta un poco al rendimiento (realmente es muy poquito), es de agradecer a la hora de programar</p>
<h2 id="holamundo">Hola Mundo</h2>
<p>Como ya he escrito bastante rollo, vamos a trabajar un pelín con go.<br>
Antes de empezar primero comprobamos que tenemos bien instalado Go, para ello desde cualquier linea de comandos (da igual Windows/Mac/Linux) escribimos:</br></p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">go version
</code></pre></div>
<p>Y deberíamos ver algo como esto:<br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-01-a-las-21.29.26.png" alt="Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion"><br>
Si lo vemos todo va bien, si a alguien no le aparece o tiene problemas que lo vaya poniendo en los comentarios y vemos como lo solucionamos.</br></img></br></p>
<p>Ahora abrimos un fichero de texto escribimos siguiente y guardamos como <strong>main.go</strong>:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">package main
import "fmt"
func main() {
fmt.Println("Hello Power Rangers")
}
</code></pre></div>
<p>Con el fichero guardado, nos situamos en la ruta donde lo tengamos en nuestra linea de comandos y ejecutamos:</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">go run main.go
</code></pre></div>
<p>Esto nos deberia mostrar algo similar a esto en la consola:<br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-01-a-las-21.42.38.png" alt="Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion"><br>
Voilá ya tenemos nuestro hola mundo. Ya iremos viendo lo que es cada cosa que hemos escrito, esto es solo para que escribamos un poco y veamos que funciona.</br></img></br></p>
<h2 id="ides">IDEs</h2>
<p>Lo último que vamos a ver en este post, serán los IDE, que yo no se vosotros, pero a mi el modo <strong>Chuck Norris</strong> para programar (hacerlo directamente en un fichero de texto) no es lo que mas me convence, si tenemos posibilidades de que nos ayuden un pelín de alguna forma yo lo agradezco, pero como ya he comentado se puede hacer con cualquier editor de texto.</p>
<p>Para programar con Go tenemos varias opciones:</p>
<ul>
<li>Podemos hacerlo en un fichero de texto(Chuck Norris/Bruce Lee/Yoda mode) como ya he comentado</li>
<li>Otra opción es usar <strong>Sublime Text</strong> una gran mayoria de vosotros ya lo conocereis, y como siempre pues tenemos plugins que la comunidad ha creado <a href="https://github.com/DisposaBoy/GoSublime">Ejemplo</a> lo que le daria algunas vitaminas a nuestro editor para trabajar con Go.</li>
<li>Tambien es posible usar <strong>Atom</strong>. Sigue la misma teoría que Sublime, tenemos plugins que nos ayudan con Go <a href="https://atom.io/packages/go-plus">Ejemplo</a></li>
<li>Los grandes de <a href="https://www.jetbrains.com/">JetBrains</a> están preparando un IDE muy completo (como siempre previo pago), y ahora tenemos disponibles algunos plugins para algunos de sus IDEs actuales.</li>
<li>Para hacer pruebas o si quereis para algunas cosas de las que vayamos viendo podemos usar el <strong>PLAYGROUND</strong> de Go <a href="https://play.golang.org/">SuperPlayground</a>, super util para compartir código.</li>
<li>Como última opción y la que más gusta es <strong>Visual Studio Code</strong>, para mi es un acercamiento a las aplicaciones de JetBrains (que para mi son de lo mejor que hay). Como es la que uso veamos un poco su configuración.</li>
</ul>
<h2 id="visualstudiocode">Visual Studio Code</h2>
<p>Con cualquier IDE y como programadores, nos pueden interesar mínimo 2 cosas para agilizar un poco nuestro trabajo:</p>
<ul>
<li>Que nos indique errores cuanto antes</li>
<li>Y poder hacer debug de nuestro código para poder resolver mejor los problemas que nos vayamos encontrando.</li>
</ul>
<p>Pues estas dos cosas y algún extra como las sugerencias son las que nos ofrece este IDE con algunas configuraciones.</p>
<p><strong>Lo primero</strong> es instalar el plugin de Go desde la aplicación. Para ello tenemos que buscar la ventana de extensiones, creo que en todas ellas esta en el menu superior de la aplicación en la pestaña <strong>ver</strong> o <strong>view</strong>, seleccionamos <strong>extensiones</strong> o <strong>extensions</strong><br>
<img srcset="/assets/images/2017/06/Screen-Shot-2017-06-02-at-21.48.18.png" alt="Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion"><br>
Y en la ventana que nos aparece buscamos <strong>Go</strong><br>
<img srcset="/assets/images/2017/06/Screen-Shot-2017-06-02-at-21.49.22.png" alt="Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion"><br>
Y entre todas las extensiones que nos aparecen buscamos la de <strong>lukehoban</strong> y la instalamos.<br>
Una vez que termine nos pedirá reiniciar la aplicación, y una vez que reinicie lo mejor es crear un fichero nuevo y ponerle extension <strong>.go</strong>.</br></br></img></br></br></img></br></p>
<p>Hacemos esta para que el propio visual studio nos complete la instalación, ya que cuando guardemos el fichero nos aparecerán algunos mensajes como este:<br>
<img srcset="/assets/images/2017/06/Screen-Shot-2017-06-02-at-21.52.55.png" alt="Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion"><br>
Básicamente en todos los que nos pregunte tenemos que indicarle <strong>Install All</strong></br></img></br></p>
<p>También es posible que nos indique que configuremos el <strong>GOPATH</strong> para que os hagáis una idea ese seria el <strong>Workspace</strong> desde donde trabajaremos, si os sale eso en <a href="https://golang.org/doc/code.html#GOPATH">Doc-GOPATH</a> o en <a href="https://golang.org/doc/install?#testing">Test Install GO</a> tenéis info para que identifiquéis bien lo que es y podáis configurarlo correctamente.</p>
<p><strong>Lo segundo</strong> es configurar para poder hacer debug, lo más fácil es que miréis en la documentación del creador <a href="https://github.com/derekparker/delve/tree/master/Documentation/installation">Derekparker-delve</a>, aquí según vuestro sistema operativo tenéis las instrucciones. En general suele valer con hacer</p>
<div class="kg-card kg-code-card gatsby-highlight" data-language="text"><pre class="language-text"><code class="language-text">go get github.com/derekparker/delve/cmd/dlv
</code></pre></div>
<p>Aunque depende un poco de la versión de sistema, como he comentado lo mejor es que miréis la documentación.<br>
Y una vez que lo tengáis instalado ya podremos ir poniendo lo que se conoce como puntos de interrupción para controlar lo que hace nuestro código.<br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-03-a-las-11.30.43.png" alt="Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion"><br>
Con hacer click un par de veces al lado del número de linea es suficiente. Y para comprobar que funciona pulsamos sobre <strong>F5</strong> o nos vamos al menú <strong>Depurar</strong> y pulsamos <strong>Iniciar depuración</strong><br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-03-a-las-11.33.03.png" alt="Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion"/></br></br></img></br></br></p>
<p>Y entonces nuestro IDE cambiará al modo <strong>debug</strong> que lo que nos hará será parar la ejecución del código donde tengamos los puntos y podemos ver como están las variables o lo que tengamos en el código.<br>
<img srcset="/assets/images/2017/06/Captura-de-pantalla-2017-06-03-a-las-11.39.06.png" alt="Go Go Power Ra....ah que no: Go Parte1 - Intro y preparacion"/></br></p>
<p>Como veis en la imagen variables a la izquierda, pila de llamadas un poco más abajo, puntos de interrupción.... todo muy útil sobretodo cuando tenemos problemas con nuestro código.</p>
<p>Y con esto finalizo este post(por fiiiin!!! ) y ya en los siguientes empezaremos con lo bueno.<br>
Si tenéis dudas o problemas ponerlo en los comentarios.<br>
Ciaaaao</br></br></p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>