<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Bitácora de Vuelo (Publicaciones sobre bibliotecas)</title><link>http://blog.taniquetil.com.ar/</link><description></description><atom:link href="http://blog.taniquetil.com.ar/categories/bibliotecas.xml" rel="self" type="application/rss+xml"></atom:link><language>es</language><copyright>Contents © 2023 &lt;a href="mailto:facundo@taniquetil.com.ar"&gt;Facundo Batista&lt;/a&gt; CC BY-NC-SA</copyright><lastBuildDate>Mon, 29 May 2023 18:52:04 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Mi posición con respecto a pinning</title><link>http://blog.taniquetil.com.ar/posts/0849/</link><dc:creator>Facundo Batista</dc:creator><description>&lt;p&gt;Si ya voy mezclando palabras raras en el título pueden empezar a adivinar que este es un post técnico, y tendrán razón.&lt;/p&gt;
&lt;p&gt;¿Qué significa &lt;em&gt;pinning&lt;/em&gt;? Un montón de cosas, pero en el mundo del software, o al menos en la parte de distribución de software, significa especificar exactamente la versión de una dependencia.&lt;/p&gt;
&lt;p&gt;Por ejemplo, yo puedo hacer un programejo que usa la biblioteca &lt;code class="docutils literal"&gt;requests&lt;/code&gt;, y no me importa la versión, entonces en la lista de dependencias pongo &lt;code class="docutils literal"&gt;requests&lt;/code&gt; y ya. Pero si quiero especificar exactamente qué versión de esa biblioteca necesito, pondría algo como &lt;code class="docutils literal"&gt;requests == 2.7.1&lt;/code&gt;. Eso es &lt;em&gt;pinnear&lt;/em&gt; (mezclando ahora inglés y castellano) la versión de la dependencia, que es como agarrarla con un alfiler para que no se mueva y siempre sea la misma.&lt;/p&gt;
&lt;img alt="Le ponemos un pin" src="http://blog.taniquetil.com.ar/images/pinning/cartelera.jpeg"&gt;
&lt;p&gt;¿Cuándo tiene sentido hacer eso y cuándo no? ¿Depende del entorno donde correrá mi programejo? ¿De las dependencias que estoy usando? ¿De la forma de distribución? Un poco de todo eso apunta a contestar este post.&lt;/p&gt;
&lt;p&gt;Entonces...&lt;/p&gt;
&lt;section id="mi-posicion-con-respecto-a-pinning"&gt;
&lt;h2&gt;Mi posición con respecto a pinning&lt;/h2&gt;
&lt;p&gt;Ya sabemos que los extremos son malos. Traducido al tema que nos atañe, podemos decir que no queremos ni nada pinneado nunca, ni todo pinneado todo el tiempo.&lt;/p&gt;
&lt;p&gt;El problema de "nada pinneado nunca" es que es muy difícil poder garantizar la calidad del sistema que estamos armando. Si en desarrollo usamos la biblioteca versión &lt;code class="docutils literal"&gt;X&lt;/code&gt;, pero luego cuando desplegamos todo en un servidor termina instalando la versión &lt;code class="docutils literal"&gt;Y&lt;/code&gt;, puede ser que nos explote todo. O peor, que parezca funcionar, pero que no funcione correctamente. Y si lo distribuimos es aún más complicado: si el sistema lo instalan un montón de personas en sus computadoras vamos a tener mil combinaciones de distintas versiones.&lt;/p&gt;
&lt;p&gt;Por otro lado, si tenemos "todo pinneado todo el tiempo", rompemos la evolución del software que contiene nuestro sistema. La evolución es un concepto central, no podemos cortar la evolución de las dependencias de nuestro software porque terminamos atados a versiones viejas. Y no es un problema de alguna funcionalidad más o menos, sino de seguridad: a menos que tengamos atrás un equipo de especialistas en seguridad haciéndose cargo del mantenimiento de versiones viejas, tenemos que tratar de usar todo lo nuevo en todos lados.&lt;/p&gt;
&lt;p&gt;Entonces, tenemos que encontrar un balance entre ambos extremos, que es lo que les comento en el resto del post.&lt;/p&gt;
&lt;p&gt;Tengamos en cuenta que queremos distintos comportamientos si tenemos bibliotecas o aplicaciones, y en este último caso dónde correrán las aplicaciones, si del lado del cliente (luego de que empaquetamos el software) o en un servidor (que desplegamos directamente).&lt;/p&gt;
&lt;img alt="Por qué les decimos bibliotecas a las bibliotecas" src="http://blog.taniquetil.com.ar/images/pinning/biblioteca.jpeg"&gt;
&lt;section id="bibliotecas"&gt;
&lt;h3&gt;Bibliotecas&lt;/h3&gt;
&lt;p&gt;Si estamos trabajando con bibliotecas, las mismas tienen que ser lo más flexibles posible, ya que van a ser usadas de maneras que no se pueden prever: nunca vamos a tener el contexto en el qué se usarán nuestras bibliotecas.&lt;/p&gt;
&lt;p&gt;Debemos especificar qué dependencias se necesitan, pero ser lo más libres y genériques posibles con respecto a las versiones, luego la aplicación que use nuestra biblioteca especificará la versión, o no. No es de nuestra incumbencia, nuestra biblioteca debería ser independiente de las versiones de sus dependencias... y aunque ya sabemos que esto no es posible en su totalidad, debemos tratar de restringir las versiones lo menos posible.&lt;/p&gt;
&lt;p&gt;En otras palabras, está mal definir que nuestra biblioteca necesita la dependencia &lt;code class="docutils literal"&gt;X&lt;/code&gt; en la versión &lt;code class="docutils literal"&gt;== 2.7.1&lt;/code&gt;, pero está bien definir que la necesita en una versión &lt;code class="docutils literal"&gt;=&amp;gt; 2&lt;/code&gt; o incluso &lt;code class="docutils literal"&gt;=&amp;gt; 2; != 2.0.4&lt;/code&gt;, en caso de que haya alguna incompatibilidad puntual. Y después será la aplicación la que defina en qué versión necesita sus propias dependencias, y se hará el análisis en conjunto para determinar si hay un conflicto. Si la biblioteca defina una dependencia &lt;code class="docutils literal"&gt;X&lt;/code&gt; en una versión específica, y la aplicación también depende de la misma &lt;code class="docutils literal"&gt;X&lt;/code&gt;, está condicionada a usar sólo esa versión. Peor aún, si la aplicación necesita las bibliotecas &lt;code class="docutils literal"&gt;foo&lt;/code&gt; y &lt;code class="docutils literal"&gt;bar&lt;/code&gt;, y &lt;code class="docutils literal"&gt;foo&lt;/code&gt; define la dependencia &lt;code class="docutils literal"&gt;X&lt;/code&gt; en una versión y &lt;code class="docutils literal"&gt;bar&lt;/code&gt; define la misma dependencia &lt;code class="docutils literal"&gt;X&lt;/code&gt; en otra versión, la aplicación directamente no podrá usar ambas &lt;code class="docutils literal"&gt;foo&lt;/code&gt; y &lt;code class="docutils literal"&gt;bar&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Entonces, recapitulemos: para las bibliotecas seamos lo menos específicos posible en las versiones de sus dependencias. Arranquemos con no indicar ninguna versión en ninguna dependencia, y vayamos agregando restricciones con el tiempo, sólo si encontramos alguna incompatibilidad.&lt;/p&gt;
&lt;img alt="Local para eventos en el lago Pavillión, en Copenhague, Dinamarca" src="http://blog.taniquetil.com.ar/images/pinning/local.jpeg"&gt;
&lt;/section&gt;
&lt;section id="aplicaciones"&gt;
&lt;h3&gt;Aplicaciones&lt;/h3&gt;
&lt;p&gt;Con las aplicaciones es diferente. En el momento en que empaquetamos una aplicación para distribuirla, o la desplegamos en servidores para ser usada, queremos poder garantizar que se ejecutará correctamente de cara a les usuaries finales.&lt;/p&gt;
&lt;p&gt;La calidad de la aplicación la garantizamos con distintas evaluaciones que hacemos, que pueden ser pruebas de unidad, pruebas de integración, pruebas manuales. Un proyecto robusto siempre tendrá alguna combinación de todas estas pruebas que se realizarán para determinar la calidad de una determinada versión de la aplicación.&lt;/p&gt;
&lt;p&gt;Pero esta versión de la aplicación, ¿qué versión de cada una de sus dependencias utilizará? Si corremos todas las pruebas para la versión que queremos liberar de nuestra aplicación usando la versión &lt;code class="docutils literal"&gt;X&lt;/code&gt; de una dependencia, pero al momento de empaquetarla o desplegarla en un servidor se termina usando la versión &lt;code class="docutils literal"&gt;Y&lt;/code&gt; de esa dependencia, en realidad las pruebas que corrimos no son válidas.&lt;/p&gt;
&lt;p&gt;Tengamos en cuenta que en realidad no hay mucha diferencia entre si a la aplicación la empaquetamos para distribuirla o la desplegamos en un servidor para ser usada. En general tanto el proceso de empaquetado como el de despliegue terminarán instalando nuevamente las dependencias necesarias, y a menos que todas las versiones estén especificadas, no tenemos control de cuales serán usadas.&lt;/p&gt;
&lt;p&gt;En otras palabras, para garantizar la calidad de la aplicación tenemos que pinnear las versiones de las dependencias, correr toda la batería de pruebas que tengamos utilizando esas dependencias, y luego empaquetar o desplegar la aplicación usando exactamente esas dependencias.&lt;/p&gt;
&lt;p&gt;Pero si tenemos todo pinneado, volvemos al problema del que hablábamos antes de poder evolucionar, quedamos atrapados en versiones viejas con posibles problemas sin corregir. O peor, con fallas de seguridad expuestas.&lt;/p&gt;
&lt;img alt="Praga, de noche, luego de la lluvia" src="http://blog.taniquetil.com.ar/images/pinning/pragamojada.jpeg"&gt;
&lt;p&gt;La forma más piola que he encontrado de tanto poder garantizar la calidad final como también de evolucionar en el tiempo es tener &lt;em&gt;dos&lt;/em&gt; listas de dependencias.&lt;/p&gt;
&lt;p&gt;La primera lista tendrá las dependencias directas de nuestra aplicación (no las dependencias de las dependencias) de la forma más laxa posible: similar a lo que hacemos con las bibliotecas, a priori no especificaremos ninguna restricción, y sólo las agregaremos con el tiempo si encontramos incompatibilidades puntuales.&lt;/p&gt;
&lt;p&gt;La segunda lista tendrá todas las dependencias de nuestra aplicación y a la vez todas las dependencias de las dependencias, y las dependencias de las dependencias de las dependencias, etc., con la versión específica con que fueron instaladas. Todas las pruebas que correrá el desarrollador, o el sistema de CI/CD (&lt;em&gt;Continuous Integration / Continuous Delivery&lt;/em&gt;) que tengamos, se harán utilizando esta segunda lista con todo bien especificado. Y el proceso posterior de empaquetado o despliegue también utilizará esta segunda lista, con lo cual terminamos garantizando la calidad de la aplicación. Incluso, si dudamos de la procedencia de los archivos de nuestras dependencias, podemos hasta sacar el &lt;em&gt;hash&lt;/em&gt; de las mismas y luego validarlas; entonces no sólo indicamos que los tests se hacen con la versión &lt;code class="docutils literal"&gt;foo == 2.1.7&lt;/code&gt; sino que también podemos validar que cuando el server instale esa versión específica el archivo con el que lo haga sea exactamente igual al que usamos nosotros, y nadie nos vendió gato por liebre en el medio (lo que sería un tipo de ataque &lt;a class="reference external" href="https://es.wikipedia.org/wiki/Ataque_de_intermediario"&gt;MITM&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Entonces, ya sabemos que tenemos dos listas para las dependencias de nuestra aplicación, la laxa que nos permite evolucionar y a partir de la cual se arma la muy específica sobre la cual se valida calidad y libera la aplicación.&lt;/p&gt;
&lt;p&gt;¿Cómo vamos de una lista a la otra? En tiempo de desarrollo. Será responsabilidad de nosotres les desarrolladores el cada tanto (no tiene que ser &lt;em&gt;todo el tiempo&lt;/em&gt;) generar el entorno de desarrollo desde cero utilizando la lista laxa y generar a partir de esa instalación la lista específica. Las distintas herramientas que nos permiten trabajar con entornos de desarrollo en general también nos dan la posibilidad de generar la lista específica a partir del entorno creado (por ejemplo en &lt;a class="reference external" href="https://fades.readthedocs.io/"&gt;fades&lt;/a&gt; tenemos la opción &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;--freeze&lt;/span&gt;&lt;/code&gt;).&lt;/p&gt;
&lt;img alt='Muy bien lograda la ambientación de una "taberna medieval" en Praga' src="http://blog.taniquetil.com.ar/images/pinning/tabernamedieval.jpeg"&gt;
&lt;p&gt;Para terminar, tengamos en cuenta que todas las dependencias que vengo mencionando son las de &lt;em&gt;producción&lt;/em&gt;, aquellas bibliotecas que nuestra aplicación necesita para finalmente correr.&lt;/p&gt;
&lt;p&gt;Pero también tenemos aquellas dependencias de &lt;em&gt;desarrollo&lt;/em&gt;: todas las bibliotecas y utilidades que usaremos les desarrolladores para, justamente, desarrollar la aplicación. Estas dependencias &lt;strong&gt;no&lt;/strong&gt; se instalarán, incluirán, ni usarán en el paquete que armemos para distribuir la aplicación o en el servidor. Un ejemplo de este tipo de dependencias podría ser &lt;a class="reference external" href="https://docs.pytest.org/"&gt;pytest&lt;/a&gt;, el corredor de pruebas de unidad.&lt;/p&gt;
&lt;p&gt;Para estas dependencias tendremos otra lista, separada de las de producción. Hay distintas formas de manejar esta separación; por ejemplo, si utilizamos archivos de dependencias podemos tener un &lt;code class="docutils literal"&gt;requirements.txt&lt;/code&gt; para las de producción y &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;requirements-dev.txt&lt;/span&gt;&lt;/code&gt; para las desarrollo.&lt;/p&gt;
&lt;p&gt;El punto es que a las dependencias de desarrollo no las tenemos que pinnear para nada (obviamente, a menos que encontremos alguna incompatibilidad o bug en particular). Siempre utilizaremos lo último de lo último cuando armemos los entornos de desarrollo, y si en algún momento algún test falla porque las herramientas que utilizamos evolucionaron (por ejemplo, &lt;a class="reference external" href="https://flake8.pycqa.org/en/latest/"&gt;flake8&lt;/a&gt; detectando un caso nuevo) corregiremos nuestro código y seguiremos adelante. Pero no hay motivo alguno para pinnearlas.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;</description><category>bibliotecas</category><category>distribución</category><category>distribution</category><category>packages</category><category>paquetes</category><category>Python</category><category>separados por pinning</category><guid>http://blog.taniquetil.com.ar/posts/0849/</guid><pubDate>Wed, 09 Nov 2022 22:19:00 GMT</pubDate></item><item><title>Bibliotequitas</title><link>http://blog.taniquetil.com.ar/posts/0561/</link><dc:creator>Facundo Batista</dc:creator><description>&lt;p&gt;Algo que venía postergando y postergando, desde hace muchos años (más de un lustro!) es el tema de traerme los libros que están en la casa de mi papá.&lt;/p&gt;
&lt;p&gt;Todavía no tengo un lugar definitivo para ponerlos, y aunque ya tenemos medio encargado un mueble para el living (el cual, en parte, contendrá algunos libros míos), seguro que necesito más espacio en otro lado.&lt;/p&gt;
&lt;p&gt;Parte de la complejidad, justamente, es no tener un lugar definitivo. Entonces, el otro día, charlando con Moni, decidimos que podía hacer unas bibliotequitas que entraran abajo de la ventana, y en dos partes, así hoy las poníamos ahí, y el día de mañana si las queríamos mover para otro lado entraran en cualquier rincón.&lt;/p&gt;
&lt;p&gt;Así que diseñé algo, compré una placa de madera en el Sodimac (indicando que la corten, obvio), ajusté, atornillé, emprolijé, pinté... y acá tienen:&lt;/p&gt;
&lt;img alt="Las bibliotequitas :)" src="http://blog.taniquetil.com.ar/images/bibliotequitas.jpeg"&gt;
&lt;p&gt;Están lindas, ¿no?&lt;/p&gt;
&lt;p&gt;Cuando las termine de llenar de libros les saco otra foto y muestro :).&lt;/p&gt;</description><category>bibliotecas</category><category>carpintería</category><category>libros</category><guid>http://blog.taniquetil.com.ar/posts/0561/</guid><pubDate>Wed, 16 May 2012 20:52:52 GMT</pubDate></item></channel></rss>