Video Summary and Transcription
¡Bienvenido a DevOpsJS 2024! Discutiremos semántica y esquemas de versionado, en particular Semantic Versioning (SEMVR). Existen preocupaciones sobre las fallas en SEMVR y la necesidad de abrazar el cambio en el desarrollo de software. El infierno de las dependencias en el ecosistema de JavaScript se ha abordado mediante el versionado semántico y nuevas capacidades. Sin embargo, todavía existen problemas con la especificación SEMBR, incluyendo definiciones ausentes y problemas con los metadatos de construcción. Para mejorar el versionado, debemos abordar las definiciones faltantes y considerar una nueva especificación para el futuro.
1. Introducción a la Semántica y la Versionización
¡Bienvenidos a DevOpsJS 2024! Hablaremos sobre semántica y esquemas de versionado, en particular el versionado semántico (SEMBR). Soy Darcy Clark, un ingeniero de software con más de 20 años de experiencia. Inspirado por la charla de Rich Hickey, tengo algunas preocupaciones sobre sus puntos de vista sobre Semver. ¡Vamos a sumergirnos!
Bienvenidos, gracias por unirse a DevOpsJS 2024 y mostrar interés en mi charla de hoy. Nos adentraremos en uno de mis temas favoritos, que es la semántica y más específicamente los esquemas de versionado, siendo el más popular el versionado semántico, también conocido como SEMBR. Primero un poco sobre mí. Mi nombre es Darcy Clark. He sido ingeniero de software durante más de 20 años, desarrollando software tanto de código abierto como cerrado. Tuve una larga carrera como consultor, trabajando con marcas increíbles, agencias y grandes empresas. También cofundé una empresa llamada Themify hace unos 10 años, que ofrece temas comerciales de WordPress y todavía está activa hoy en día. Pasé los últimos cuatro años trabajando en NPM en GitHub, en los equipos de la interfaz de línea de comandos (CLI) tanto de GitHub como de NPM. Estoy construyendo un nuevo registro y cliente de paquetes JavaScript en una empresa que fundé el año pasado llamada Volt, y puedes obtener más información en VLT.SH. Esta charla en realidad fue inspirada por una charla de Rich Hickey. En 2016, hizo una presentación llamada Especulación, en la que profundiza en el versionado de software y en el propio versionado semántico. Si no has visto alguna de sus charlas antes, te recomiendo encarecidamente que vayas a YouTube y eches un vistazo a su trabajo. Esta charla en particular es increíble, y creo que él es un gran orador con ideas impresionantes. Dicho esto, tengo algunas preocupaciones con algunas de las conclusiones clave de la charla de Rich, su charla de especulación. Hasta donde puedo ver, nadie ha planteado problemas en los últimos siete años, así que espero no estar solo.
2. Desafíos con Semver y Abrazar el Cambio
Rich cree que Semver tiene fallas y solo acepta cambios compatibles hacia atrás. Yo creo que el software debe reflejar la vida real, abrazando errores y cambios. La estancación y la excesiva permisividad pueden llevar a interfaces sobrecargadas. El versionado de software debe anticipar y comunicar los cambios necesarios.
El primero de ellos es que Rich cree ampliamente que Semver es una especificación deficiente. No estoy completamente en contra de él en este punto. Creo que hay mucho margen de mejora, y definitivamente profundizaremos en eso un poco más adelante. La segunda afirmación principal y conclusión es que nunca deberíamos lanzar cambios disruptivos, o si necesitamos lanzar cambios disruptivos, deberíamos hacerlo bajo un nuevo nombre. En otras palabras, él cree que los únicos cambios aceptables en el software deberían ser los compatibles hacia atrás. Y, por supuesto, por último, está de acuerdo con la idea de la estancación del software, lo cual está en línea con el segundo punto. Para mí, creo que la creación y versionado del software deberían imitar la vida real. A veces las cosas cambian y los cambios no son perfectos. Rompemos cosas, y eso es parte de la vida. No deberíamos tener miedo de cometer errores, y deberíamos sentirnos obligados a crear entornos donde sea fácil aprender con un impacto externo mínimo cuando nos equivocamos. En el caso de la estancación, es un fenómeno natural, pero no es algo que debamos promover o pensar que es positivo. La estancación del software es lo mismo. Negarse a fomentar y mantener el software significa que probablemente tendrá un final similar al del mundo real. La muerte, o peor aún, la irrelevancia. Cuando hablamos de flexibilizar las restricciones o crear una API más amplia, volvemos a encontrarnos en un territorio antinatural e incómodo nuevamente. Ser más permisivos con el software significa que con el tiempo terminarás con una interfaz pública sobrecargada que debes mantener. Esta es una carga autoimpuesta que solo puede ser reflejada a través de cambios disruptivos. Esto es similar a cómo es posible que necesites romper malos hábitos en el mundo físico. Pero eso termina prolongando tu vida útil. Por último, considero totalmente antinatural contaminar nuestros ecosistemas con espacios de nombres falsos. Nuestros esquemas de versiones deberían liberarnos de los contratos restrictivos que tenemos con interfaces históricas, siempre y cuando el propósito subyacente del proyecto no haya cambiado. Este punto de vista que tengo proviene de mi comprensión de que el software y el versionado de software son caóticos, al igual que la vida. El software cambia con el tiempo, y esto refleja cómo todos aprendemos y crecemos orgánicamente. Los cambios en el software pueden romper cosas, al igual que en el mundo real. No todos los cambios son esperados, y a veces rompen. Pero debemos respetar y aceptar que los cambios disruptivos son parte de la vida y son parte del crecimiento. Tener un esquema en su lugar que anticipe eso como algo necesario, es fundamental para crear un ecosistema próspero de software versionado. A veces, los cambios incluso pueden quitar cosas, lo cual es otro tipo de ruptura y cambio. Pero nuevamente, esto refleja la vida real. Y en última instancia, una especificación de versionado de software
3. Dependency Hell and the JavaScript Ecosystem
La versión semántica es una solución para el infierno de las dependencias, que tiene nueve círculos de problemas. Sunbird no resolvió el primer círculo, pero Node y NPM sí lo hicieron. El ecosistema de JavaScript ha adoptado la versión semántica y ha agregado nuevas reglas y capacidades para evitar el infierno de las dependencias.
La versión semántica tiene como objetivo codificar las señales de comunicación del cambio. Es un lenguaje en sí mismo y solo será tan bueno como las definiciones que abarque. Veamos la versión semántica. Citando directamente la especificación original de Sunverse, en el mundo de la gestión de software existe un lugar temido llamado infierno de las dependencias. Cuanto más crecen tus sistemas, más paquetes integras, más probable es que algún día te encuentres en este pozo de desesperación. Como puedes ver, la versión semántica se presenta como una solución a algo llamado infierno de las dependencias. En realidad, sostengo que hay nueve niveles, o nueve círculos, que representan el infierno de las dependencias. Al igual que en los nueve círculos del infierno de Dante, tenemos nueve círculos del infierno de las dependencias. Si sabes algo sobre los nueve círculos de Dante, sabrás que el primer círculo es el limbo. Podemos colocar en el ecosistema cualquier ecosistema o usuario que elija no consumir dependencias en este primer nivel. Bajando, llegamos a la lujuria, donde no te importa qué dependencias obtienes. Luego llegamos a la gula, donde no te importa cuántas dependencias obtienes, y así sucesivamente.
En la charla de Rich, muestra un diagrama de un gráfico de dependencias de palma del mundo Java, donde hay múltiples dependencias que tienen relaciones de dependencia transitiva que deben satisfacerse. Para la mayoría de los lenguajes, esto es un gran problema, porque a menudo surgen conflictos cuando solo puedes tener una versión de cualquier cosa en tu proyecto. Este problema impide que muchos ecosistemas consuman dependencias y terminen en un estado de limbo. En términos de este infierno de las dependencias, creo que este fue y es el primer círculo. Entonces, la historia aquí es que Sunbird en realidad no resolvió el primer círculo del infierno de las dependencias para nadie en absoluto. Como te mostré, en realidad hay otros círculos de problemas a los que debemos abordar y llegar. Pero algunas personas inteligentes sí resolvieron este problema. En 2010, Node introdujo módulos comunes y NPM, que era el nuevo gestor de paquetes en ese momento. Debido a que Node admite la inclusión de módulos anidados, significa que puedes delimitar de manera segura mientras consumes dependencias transitivas conflictivas. No hay un contexto global. Puedes duplicar las referencias de una dependencia en tiempo de ejecución mientras las deduplicas en la caché. El enfoque aquí en JavaScript se centra en la programación funcional con la menor cantidad de efectos secundarios posible.
Entonces, ¿cuál es el estado del ecosistema de JavaScript hoy en día en cuanto al infierno de las dependencias? Bueno, lo hemos hecho bastante bien. Como puedes ver, los paquetes publicados en NPM superan con creces a cualquier otro ecosistema. Parece que nuestra comunidad ha adoptado realmente la versión semántica evitando también el primer círculo del infierno de las dependencias. El secreto aquí, y spoiler, es que en realidad no usamos la versión semántica tal como se especificó. La biblioteca que se utiliza en el cliente NPM y el registro agrega nuevas reglas y capacidades que no están realmente en la especificación de la versión semántica 2.00. Esto incluye cosas como conjuntos, rangos, comparadores y las definiciones y lógica de operadores correspondientes. Si solo usáramos la especificación de la versión semántica tal como está escrita hoy, no creo que tendríamos
4. The Sixth Circle of Dependency Hell
Nos enfrentamos al sexto círculo del infierno de las dependencias, conocido como herejía. Nuestro ecosistema carece de autocontrol en el consumo de dependencias, como se muestra por la cantidad excesiva de paquetes instalados. Los gestores de paquetes interpretan la especificación de manera diferente, lo que lleva a inconsistencias. Sin embargo, hay esperanza.
Hemos tenido éxito como comunidad. El nuevo problema al que nos enfrentamos es que hemos caído en el sexto círculo del infierno de las dependencias, al que llamamos herejía. Puede que te preguntes qué ha pasado con los círculos 2 al 5, y lo que quizás no te des cuenta es que esos son prácticamente el statu quo para cualquier ecosistema próspero. Como puedes ver aquí, los círculos 2 al 5 se consideran los círculos de la incontinencia, lo que simplemente significa falta de autocontrol. Creo que esto tiene sentido en el contexto de la relación actual de nuestro ecosistema con las dependencias. Somos lujuriosos, glotones, codiciosos y a veces incluso enojados. Mirando los datos nuevamente, esto parece estar en línea con cómo esperas que nuestra comunidad crezca y consuma dependencias. Un gran ejemplo de esta falta de autocontrol se muestra aquí a la derecha. Puedes ver cuántas dependencias se instalan con cada gestor de paquetes para un proyecto básico de creación de una aplicación de React. Esto no es la forma más moderna de crear un proyecto de React, pero es solo para mostrar dos cosas diferentes. Aproximadamente se instalan 1.200 dependencias solo para iniciar un proyecto pequeño, y hay una gran discrepancia en el número de paquetes que se descargan en estas herramientas. Puede que te preguntes qué está pasando aquí. ¿Por qué está sucediendo esto? ¿Cómo es posible? Bueno, los gestores de paquetes interpretan la especificación de manera diferente en cada una de las herramientas. Esto significa que tu gráfico de dependencias será diferente según la herramienta que estés utilizando. Esto es exactamente lo que parece el sexto círculo del infierno de las dependencias. Herejía. No hay un estándar o al menos no hay un estándar que se siga de manera consistente en nuestras herramientas de empaquetado.
5. Problemas con la especificación SEMBR
SEMBR tiene buenas intenciones pero está plagado de definiciones malas y ausentes. La especificación actual tiene 11 años y presenta problemas con las versiones de parche y las compilaciones. La definición oficial de un parche es la compatibilidad hacia atrás, lo cual es prácticamente imposible. La definición de las compilaciones en la especificación fue cambiada, lo que ha causado consecuencias importantes. SEMBR 2.0.0-rc1 es la especificación más precisa para la numeración de versiones.
En este punto, probablemente estés pensando que estos son problemas que parecen sistémicos y que estamos definitivamente en una situación difícil. Pero te prometo que hay esperanza.
Entonces echemos un vistazo al estado actual de la especificación SEMBR en sí misma. Es importante destacar que SEMBR y las personas detrás de ella tienen buenas intenciones, pero desafortunadamente, en mi opinión, SEMBR está plagado de definiciones malas y extrañamente ausentes. Si aún no lo has hecho, lee la especificación en Sembr.org. La especificación actual, SEMBR 2.0.0, tiene aproximadamente 11 años y consta de 11 reglas. La versión normal básica en SEMBR se considera compuesta por una versión principal, una versión secundaria y una versión de parche. La versión principal representa cambios incompatibles en la API, la versión secundaria representa funcionalidad o capacidades adicionales que son compatibles hacia atrás, y la versión de parche representa correcciones destinadas a solucionar errores en la funcionalidad existente. Hay matices en esto, donde puedes encontrar fragmentos de versiones normales en materiales de marketing populares como 1.0, 3.0. Y se entiende que los valores se leen de izquierda a derecha y la precedencia de las versiones está bien definida. Entonces echemos un vistazo a algunas de las extensiones de SEMBR. Además de la versión normal, hay dos extensiones en la especificación SEMBR. Ambas versiones preliminares se definen con un guión, que las separa de la versión normal. Y los metadatos de compilación también se pueden agregar al final de la versión, separados por un signo más. En general, todos los componentes de una versión semántica son como se define hoy en día. Con esa visión general básica, profundicemos en las definiciones que la especificación actual tiene incorrectas. El primer problema que puedes encontrar con la especificación es en realidad la definición de un parche. La especificación oficial de SEMBR señala que las versiones de parche deben ser compatibles hacia atrás, lo cual es prácticamente imposible. La idea detrás de una corrección de errores es corregir un comportamiento que no fue intencional. No que sea incompatible con el comportamiento anterior. El lenguaje aquí debe ser modificado o de lo contrario se codificarán errores como características y viceversa. Esto anula la utilidad conceptual de un parche, lo cual obviamente es malo. Pero hay una definición aún peor y más importante en la especificación actual que debe ser cambiada. Eso es la compilación. Cuando se redactó por primera vez la versión 2.0.0 de la numeración semántica por Tom Preston Warner, él define compilaciones, no metadatos de compilación. Dos años después, dos personas del ecosistema de NuGet vinieron y cambiaron el propósito de las compilaciones, volviéndolas y su definición efectivamente inútiles. SEMBR 2.0.0-rc1 es, hasta donde puedo decir, la especificación más precisa para la numeración de versiones y abarca la práctica común de generar compilaciones o variantes de compilación. Estos cambios disruptivos en la especificación nunca deberían haber sido introducidos y han causado consecuencias sutiles pero importantes. En la especificación original SEMBR 2.0.0-rc1, las compilaciones funcionaban como el antítesis de las versiones preliminares. Incluso podrías llamarlas versiones posteriores si lo deseas.
6. Problemas con la numeración semántica y los metadatos de compilación
El problema es que las versiones con metadatos de compilación deberían tratarse de manera distinta pero no lo están actualmente. La implementación de Sembr de NPM elimina por defecto los metadatos de compilación, lo que causa confusión en el ecosistema. Introducir una gramática no funcional para comentarios sería una solución más clara.
quería. Como puedes ver aquí, se respetan al considerar los precedentes o el orden de las versiones. Cuando introdujimos cambios en el significado de las compilaciones a los metadatos de compilación, eliminaron los precedentes de una compilación, haciendo que cualquier versión con metadatos de compilación sea equivalente a cualquier otra versión normal o de prerelease. Esto crea una situación en la que no hay definición o forma de ordenar una versión que incluya metadatos de compilación. En este ejemplo, seis piezas diferentes de software con diferentes hashes de Git y diferentes arquitecturas son todas equivalentes desde el punto de vista semántico. No hay forma en la especificación actual de hacer algo con ellas. Estarías equivocado si pensaras que hay algún criterio para cómo emparejar una de estas o elegir una de estas sobre otra. Este problema empeora por el hecho de que la implementación de Sembr de npm, que curiosamente crea sus propias gramáticas y lógica adicionales sobre la especificación, elimina por defecto los metadatos de compilación de una versión. Esto significa que hoy en día, no hay paquetes en nuestro ecosistema que tengan metadatos de compilación, lo cual se supone que sigue siendo un valor válido de versión semántica. Entonces, para resumir, el problema aquí es que la versión semántica que incluye metadatos de compilación debería tratarse de manera distinta pero no lo está actualmente. De hecho, no tenemos forma de diferenciar entre dos versiones con metadatos de compilación definidos. Pero las versiones de software con metadatos de compilación no son metadatos en sí mismos. Son piezas de software distintas. En cambio, como hemos definido anteriormente, deberíamos tratar las versiones con metadatos de compilación como compilaciones, que son el antítesis de una versión de prerelease. Parece absurdo decirlo, pero si quisiéramos introducir una gramática no funcional en una especificación, debería haberse hecho explícitamente para comentarios. Apropiarse del valor existente y del caso de uso legítimo de las compilaciones solo ha confundido al ecosistema y a las herramientas disponibles. En este ejemplo, puedes ver cómo se vería la introducción de un nuevo valor con comentarios precedidos por un símbolo de almohadilla y sin valor empírico o efecto en el
7. Definiciones faltantes en la numeración semántica
Al combinar estos cambios, abordamos las definiciones faltantes de la numeración semántica, incluyendo contexto, conjuntos y subconjuntos. La biblioteca no estándar de NPM proporciona soluciones. Los operadores de rango y los conjuntos de compilación ayudan con la comparación y filtrado de versiones. También necesitamos definir conjuntos ordenados y no ordenados.
precedencia. Al combinar todos estos posibles cambios juntos, puedes ver que una compilación ahora tendría su precedencia relativa nuevamente y los comentarios alfanuméricos aún pueden definirse pero no tienen significado. Esto nos lleva a las definiciones faltantes de la numeración semántica.
Lo más notable es la completa falta de contexto para describir el software, o los proyectos en sí mismos en la especificación actual de Sanvers. Leyendo directamente de la especificación actual, los números de versión y la forma en que cambian transmiten el significado sobre el código subyacente y lo que se ha modificado de una versión a la siguiente. Inherente a esto, hay una conexión entre las versiones y el contexto en el que se aplican. En este ejemplo, muestro cómo podría verse un esquema de contexto al anteponer una versión normal con un contexto alfanumérico, separado por un símbolo de arroba, que es común. Esta definición seguramente te resultará familiar porque lo vemos todo el tiempo en nuestros ecosistemas de gestión de paquetes existentes, especialmente NPM JavaScript.
Otra definición clave que falta es el concepto de conjuntos. Puede parecer pedante, pero no definir conjuntos o cómo se pueden crear, ordenar o desordenar los conjuntos, deja lagunas fundamentales en nuestra comprensión colectiva de cómo gestionar más de una versión de software. Como se mencionó, la especificación actual solo define la precedencia. En este caso, 1.0.0 es mayor que 2.1.6 y luego 2.3.9. La precedencia en sí misma no nos brinda suficiente claridad o lenguaje para crear y gestionar conjuntos de versiones.
Aquí es donde la biblioteca no estándar de NPM ha venido históricamente al rescate y ha llenado muchas de estas lagunas. Esta biblioteca maneja todo excepto la obtención de contexto de una versión. Si profundizas, descubrirás que NPM también ha resuelto ese problema. La biblioteca NPM package arg analizará el contexto de valores de versión no estándar, pero más completamente conceptualizados. Por ejemplo, react en carats 1, 2, 3. Esta biblioteca utiliza la biblioteca semver de nodo anterior bajo el capó. Entonces, ¿cómo se vería una definición de conjunto faltante para semver? Bueno, incluiría el contexto del software y una definición de conjuntos de versiones de software individuales. Esto codificaría los conjuntos inherentes del software. En estos dos ejemplos anteriores, puedes ver que las versiones de react no se pueden y no se deben comparar con las versiones de express. Este es el primer tipo de conjunto, el conjunto contextual. A continuación de los ejemplos, verás definiciones de los operadores de rango faltantes, que a menudo se incluyen en los gestores de paquetes, el más notable de los cuales es el asterisco o xgrammar, que coincide con cualquier versión dentro de un conjunto relativo. Aquí están los tres conjuntos faltantes para normal, prelanzamiento y postlanzamiento, también conocidos como conjuntos de compilación. Definirlos explícitamente nos permite saber cuándo estamos incluyendo o filtrando versiones particulares para comparación. Estas son delimitaciones útiles tanto para el consumidor como para el autor de la herramienta. Penúltimo, llegamos al concepto faltante de subconjuntos. En este ejemplo, puedes ver todos los diferentes subconjuntos que existen dentro de cada una de las versiones semánticas particulares. Estos representan todas las posibles versiones que podrían existir dentro
8. El Futuro de la Numeración Semántica
La especificación actual carece de la capacidad para manejar conjuntos desordenados. La numeración semántica 2.0 está desactualizada y no hay posibilidad de un lanzamiento 3.0. Para evitar el infierno de dependencias, necesitamos una nueva especificación. Consulta Sember.xyz para obtener actualizaciones. Se necesitan nuevas herramientas, infraestructura y responsables. Mejoremos el lenguaje para un crecimiento y éxito continuo en el ecosistema.
el contexto del proyecto. Y por último, debemos definir conjuntos ordenados y desordenados. La especificación actual solo infiere que se pueden usar precedentes para ordenar un conjunto, pero debemos asumir que se nos darán conjuntos desordenados. ¿Qué sigue? Tenemos todas estas ideas nuevas y potencialmente impactantes, definiciones y enmiendas que agregan mucho valor y pueden aportar mayor claridad a nuestra especificación compartida. ¿Qué debemos hacer? Bueno, desafortunadamente, la numeración semántica 2.0 tiene más de 11 años. Nada ha cambiado al respecto en todo ese tiempo. Las enmiendas y mejoras efectivamente se han estancado y parece que no hay posibilidad realista de lanzar una versión 3.0. Para que podamos aprovechar todas las soluciones existentes y nuevas que tenemos para evitar más círculos de infierno de dependencias, necesitamos codificar esto en una nueva especificación para no convertirnos en herejes. Si quieres seguir el trabajo que estoy haciendo en este espacio, visita el sitio web, Sember.xyz. Por supuesto, también necesitaremos nuevas herramientas e infraestructura para operacionalizar esta especificación. Estoy haciendo eso mismo con mi empresa VLT. Además, necesitamos presentar nuevos responsables para la especificación. ECMA es un buen lugar para losestándares, y necesitamos encontrar un nuevo hogar o entidad para encargarse de esta especificación en el futuro. Creo que si hacemos las cosas bien, mejoraremos el statu quo del lenguaje que usamos para definir nuestro software y estaremos preparados para un crecimiento y éxito continuo en esteecosistema durante mucho tiempo en el futuro. Muchas gracias por escucharme hoy. Si quieres contactarme o conectarte conmigo, mi usuario es @Darcy en Twitter o visita el nuevo registro de paquetes que estoy construyendo en VLT.sh. Gracias.
Comments