Capítulo 7. Empaquetado, Liberación, y Desarrollo diario

Tabla de contenidos

Numeración de versiones liberadas
Componentes del número de versión liberada
La Estrategia Simple
La estrategia Par/Impar
Release Branches
Mechanics of Release Branches
Stabilizing a Release
Dictatorship by Release Owner
Change Voting
Managing collaborative release stabilization
Release manager
Packaging
Format
Name and Layout
To capitalize or not to capitalize
Pre-releases
Compilation and Installation
Binary Packages
Testing and Releasing
Candidate Releases
Announcing Releases
Maintaining Multiple Release Lines
Security Releases
Releases and Daily Development
Planning Releases

Este capítulo trata sobre cómo los proyectos de software libre empaquetan y liberan su software, y cómo los patrones de desarrollo generales se organizan en torno a esos objetivos.

Una de las mayores diferencias entre los proyectos de código abierto y los propietarios es la falta de control centralizado sobre el equipo de desarrollo. Cuando una nueva versión está siendo preparada, esta diferencia es especialmente notable: una empresa puede orientar a todo el equipo de desarrollo a centrarse únicamente en la futura versión, dejando de lado nuevos desarrollos futuros y la solución de bugs no críticos hasta que la versión sea liberada. Los grupos de voluntarios no son tan monolíticos. La gente participa en los proyectos por todo tipo de razones, y aquellos que no estén interesados en ayudar con una versión dada todavía querrán continuar con su trabajo regular de desarrollo mientras la versión se está realizando. Dado a que el desarrollo nunca finaliza, el proceso de liberación de versiones del Open Source tiende a alargarse, pero es menos disruptivo, que el proceso de liberación del software comercial. Es algo similar a la reparación de una larga carretera. Hay dos maneras de reparar una carretera: puedes cerrarla completamente, para que un equipo de reparaciones pueda estar completamente sobre ella hasta que el problema se solucione, o puedes trabajar en un par de carriles a un tiempo, mientras dejas los otros abiertos al tráfico. La primera forma es más eficiente para el equipo de reparación , pero para nadie más—la carretera está completamente cerrada hasta que finalice el trabajo. La segunda manera supone más tiempo y problemas para el equipo de reparaciones (ahora ellos tendrán que trabajar con menos gente y menos equipamiento, en apretadas condiciones, con auxiliares para frenar y dirigir el tráfico, etc.), pero al menos la carretera permanece abierta, aunque no sea con la capacidad total.

Los proyectos de código abierto tienden a trabajar de la segunda manera. De hecho, para una pieza madura de software con diversas líneas de versiones diferentes siendo mantenidas simultáneamente, el proyecto está en una especie de estado permanente de reparaciones menores de la carretera. Hay siempre un par de carriles cerrados; el grupo de desarrollo en general siempre tolera un nivel de inconvenientes de fondo constante pero bajo, para que las liberaciones se hagan bajo una planificación regular.

El modelo que posibilita esto se generaliza a algo más que sólo la liberación de versiones. Es el principio de paralelización de tareas que no son interdependientes —un principio que de ningún modo es exclusivo del desarrollo de software de código abierto, por supuesto, pero los proyectos de código abierto lo implementan de una manera particular. No pueden darse el lujo de molestar demasiado al personal de la carretera ni al tráfico regular, pero tampoco pueden permitirse que haya personas dedicadas a pararse junto a los conos de color naranja y controlar el tráfico. Por lo tanto, gravitan en torno a procesos que tienen niveles planos y constantes de esfuerzo de administración, en lugar de altos y bajos. Los desarrolladores generalmente están dispuestos a trabajar con cantidades pequeñas pero consistentes de inconvenientes; la predicibilidad les permite ir y venir sin preocuparse acerca de si sus planificaciones entran en conflicto con lo que ocurre en el proyecto. Pero si el proyecto estuviera sujeto a una planificación maestra en la cual unas actividades excluyen a otras, el resultado sería que muchos desarrolladores permanecerían inactivos la mayor parte del tiempo — que sería, no sólo ineficiente, sino aburrido, y por tanto peligroso, ya que un desarrollador aburrido está cerca de convertirse en un ex-desarrollador.

El trabajo de liberación de versiones suele ser la tarea de no-desarrollo más perceptible que ocurre en paralelo con el desarrollo, por lo que los métodos descritos en las siguientes secciones están orientados principalmente a habilitar las liberaciones. Sin embargo, nota que esto también aplica a otras tareas paralelizables, tales como traducciones e internacionalizaciones, amplios cambios en la API realizados gradualmente en todo el código base, etc.

Numeración de versiones liberadas

Antes de que hablemos de cómo liberar una versión, echemos un vistazo a cómo nombrar el lanzamiento, lo cual requiere saber qué significan en realidad para los usuarios las versiones liberadas. Una versión liberada significa que:

  • Algunos errores viejos han sido corregidos. Esta es probablemente la única cosa en la que los usuarios pueden contar como verdadera de cada versión.

  • Se han añadido nuevos errores. Por lo general, también se puede contar con esto, excepto a veces en el caso de lanzamientos de seguridad u otros eventos únicos (ver “Security Releases” más adelante en este capítulo).

  • Nuevas características pueden haber sido agregadas.

  • Nuevas opciones de configuración pueden haber sido agregadas, o el significado de viejas opciones puede haber sido cambiado sutilmente. También pueden haber cambiado los procedimientos de instalación desde la última liberación, aunque uno siempre espera que no.

  • Es posible que se hayan introducido cambios incompatibles, por ejemplo, que los formatos de datos utilizados por versiones anteriores del software ya no se puedan utilizar sin someterse a algún tipo de instancia de conversión unidireccional (posiblemente manual).

Como puedes ver, no todas estas cosas son buenas. Esta es la razón por la que los usuarios experimentados se aproximan a las nuevas versiones liberadas con cierta inquietud, especialmente cuando el software es maduro y ya estaba en su mayoría haciendo lo que querían (o pensaban que querían). Incluso la llegada de nuevas funciones es una bendición mixta, ya que puede significar que el software ahora se comportará de formas inesperadas.

El propósito de la numeración de las versiones liberadas, por lo tanto, es doble: obviamente, los números deben comunicar sin ambigüedad el orden de las versiones dentro de una serie dada (es decir, al mirar los números de cualquiera de las dos versiones en la misma serie, uno puede saber cuál vino más adelante), pero también deben indicar de la manera más compacta posible el grado y la naturaleza de los cambios en cada versión.

¿Todo eso en un número? Bueno, más o menos, sí. Las estrategias de numeración de versiones liberadas son de las discusiones más antiguas (ver “Cuanto más blando sea el tema, más largo será el debate” en Capítulo 6, Comunicaciones), y es improbable que en el futuro cercano se establezca un solo estandard en el mundo. Sin embargo, han surgido algunas buenas estrategias, junto con un principio universalmente aceptado: ser consistente. Seleccionar un esquema de numeración, documentarlo, y apegarse a él. Tus usuarios te lo agradecerán.

Componentes del número de versión liberada

Esta sección describe en detalle las convenciones habituales de numeración de lanzamientos y supone muy poco conocimiento previo. Su propósito es principalmente como referencia. Si ya estás familiarizado con estas convenciones, puedes omitir esta sección.

Los números de versión liberada son grupos de dígitos separados por puntos:

Scanley 2.3
Singer 5.11.4

...etcétera. Los puntos no son puntos decimales, son solo separadores; "5.3.9" sería seguido por "5.3.10". Ocasionalmente algunos proyectos insinuan otro significado, el más famoso es el kernel de Linux con su secuencia "0.95", "0.96"... "0.99" que conduce a Linux 1.0, pero la convención de que los puntos no son decimales está firmemente establecida y debería ser considerada como estándar. No hay límite en el número de componentes (porciones de dígitos que no contienen puntos), pero la mayoría de los proyectos no van mas allá de tres o cuatro. Las razones de por qué se aclararán más adelante.

Adicionalmente a los componentes numéricos, algunas veces los proyectos agregan una etiqueta descriptiva como "Alfa" o "Beta" (ver Alfa y Beta), por ejemplo:

Scanley 2.3.0 (Alfa)
Singer 5.11.4 (Beta)

Un clasificador como Alfa o Beta significa que esta versión liberada precede a una versión de futura liberación que va a tener el mismo número sin el clasificador. Así, "2.3.0 (Alfa)" conduce eventualmente a "2.3.0". Con el fin de permitir varias versiones candidatas de una sola vez, los clasificadores en sí mismos pueden tener meta-clasificadores. Por ejemplo, aquí una serie de versiones en el orden en el que estarán disponibles al público:

Scanley 2.3.0 (Alfa 1)
Scanley 2.3.0 (Alfa 2)
Scanley 2.3.0 (Beta 1)
Scanley 2.3.0 (Beta 2)
Scanley 2.3.0 (Beta 3)
Scanley 2.3.0

Observa que cuando tiene el calificador "Alfa", Scanley "2.3" se escribe como "2.3.0". Los dos números son equivalentes —los componentes finales con cero siempre pueden eliminarse por brevedad, pero cuando hay un calificador presente, la brevedad está fuera de alcance de todos modos, por lo que uno podría optar por la exhaustividad.

Otros calificadores en uso semi-regular incluyen "Estable", "Inestable", "Desarrollo" y "RC" (para "Versión candidata"). Los más utilizados siguen siendo "Alfa" y "Beta", con "RC" en un tercer lugar cercano, pero ten en cuenta que "RC" siempre incluye un meta-calificador numérico. Es decir, no liberas "Scanley 2.3.0 (RC)", liberas "Scanley 2.3.0 (RC 1)", seguido de RC2, etc.

Esas tres etiquetas, "Alfa", "Beta" y "RC", son bastante conocidas ahora, y no recomiendo usar ninguna de las otras, aunque las otras a primera vista parezcan mejores opciones porque son palabras normales, no jerga. Pero las personas que instalan software desde versiones liberadas ya están familiarizadas con las tres grandes, y no hay razón para hacer las cosas de manera gratuita diferente a la forma en que todos los demás las hacen.

Aunque los puntos en los números de lanzamiento no son puntos decimales, sí indican la importancia del valor de posición. Todos los lanzamientos "0.X.Y" preceden a "1.0" (que es equivalente a "1.0.0", por supuesto). "3.14.158" precede inmediatamente a "3.14.159", y precede no inmediatamente a "3.14.160" así como a "3.15.cualquier cosa", y así.

Una política de numeración de versiones liberadas consistente le permite al usuario mirar dos números de versión para la misma pieza de software y decir, solo a partir de los números, las diferencias importantes entre las mismas. En un sistema típico de tres componentes, el primer componente es el número principal , el segundo es el número menor , y el tercero es el número micro  (a veces también se le llama número "parche"). Por ejemplo, la versión liberada "2.10.17" es la decimoctava versión liberada micro (o versión liberada de parche) en la undécima línea de versiones liberadas menores dentro de la segunda serie de versiones liberadas principales. Las palabras "línea" y "serie" se usan informalmente aquí, pero significan lo que uno esperaría: una serie principal es simplemente todas las versiones liberadas que comparten el mismo número principal, y una serie menor (o línea menor) consiste en todos las versiones liberadas que comparten el mismo número menor y número principal. Es decir, "2.4.0" y "3.4.1" no están en la misma serie menor, a pesar de que ambas tienen "4" para su número menor; por otro lado, "2.4.0" y "2.4.2" están en la misma línea menor, aunque no son adyacentes si se liberó "2.4.1" entre ellas.

Los significados de estos números son exactamente lo que cabría esperar: un incremento del número principal indica que se produjeron cambios importantes; un incremento del número menor indica cambios menores; y un incremento del número micro indica cambios realmente triviales. Algunos proyectos agregan un cuarto componente, generalmente llamado número de parche,  para un control especialmente específico sobre las diferencias entre sus versiones liberadas (confusamente, otros proyectos usan "parche" como sinónimo de "micro" en un sistema de tres componentes). También hay proyectos que utilizan el último componente como un número de compilación , que se incrementa cada vez que se construye el software y que no representa ningún cambio más que esa compilación. Esto ayuda al proyecto a vincular cada informe de error con una compilación específica, y es probablemente más útil cuando los paquetes binarios son el método predeterminado de distribución.

Aunque existen muchas convenciones diferentes sobre cuántos componentes usar y qué significan los componentes, las diferencias tienden a ser menores —se obtiene un poco de margen de maniobra, pero no mucho. Las siguientes dos secciones discuten algunas de las convenciones más utilizadas.

La Estrategia Simple

La mayoría de los proyectos tienen reglas sobre qué tipo de cambios se permiten en una versión liberada si una solo incrementa el número micro, diferentes reglas para el número menor y aún diferentes para el número principal. Todavía no hay un estándar establecido para estas reglas, pero aquí describiré una política que ha sido utilizada con éxito por varios proyectos. Es posible que desees simplemente adoptar esta política en tu propio proyecto, pero incluso si no lo haces, sigue siendo un buen ejemplo del tipo de información que los números de versión liberada deben transmitir. Esta política está adaptada del sistema de numeración utilizado por el proyecto APR, ver http://apr.apache.org/versioning.html.

  1. Los cambios solo en el número micro (es decir, los cambios dentro de la misma línea menor) deben ser compatibles con versiones anteriores y posteriores. Es decir, los cambios deben ser solo correcciones de errores o mejoras muy pequeñas en las características existentes. Las nuevas características no deben introducirse en una versión micro.

  2. Los cambios en el número menor (es decir, dentro de la misma línea principal) deben ser compatibles con versiones anteriores, pero no necesariamente compatibles con versiones posteriores. Es normal que se introduzcan nuevas funciones en una versión menor, pero generalmente no hay demasiadas funciones nuevas a la vez.

  3. Cambios en el número principal marcan límites de compatibilidad. Una nueva versión principal puede ser incompatible con versiones anteriores y posteriores. Se espera que una versión importante tenga nuevas características, e incluso puede tener conjuntos de características completamente nuevos.

Lo que significa exactamente compatible con versiones anteriores y compatible con versiones posteriores depende de lo que haga tu software, pero en contexto generalmente no están abiertos a mucha interpretación. Por ejemplo, si tu proyecto es una aplicación cliente/servidor, entonces "compatible con versiones anteriores" significa que actualizar el servidor a 2.6.0 no debería hacer que ningún cliente 2.5.4 existente pierda la funcionalidad o se comporte de manera diferente a como lo hacía antes (a excepción de bugs que fueron arreglados, por supuesto). Por otro lado, la actualización de uno de esos clientes a 2.6.0, junto con el servidor, podría hacer que la nueva funcionalidad esté disponible para ese cliente, funcionalidad que los clientes de la versión 2.5.4 no saben cómo aprovechar. Si eso sucede, entonces la actualización no es "compatible con versiones posteriores": claramente no se puede volver a la versión 2.5.4 de ese cliente y mantener toda la funcionalidad que tenía en 2.6.0, ya que parte de esa funcionalidad era nueva en 2.6.0.

Esta es la razón por la que las versiones liberadas micro son esencialmente solo para corregir errores. Deben seguir siendo compatibles en ambas direcciones: si actualiza de 2.5.3 a 2.5.4, luego cambia de idea y baja de nuevo a 2.5.3, no se debe perder ninguna funcionalidad. Por supuesto, los errores corregidos en 2.5.4 reaparecerían después de volver hacia atrás, pero no perdería ninguna característica, excepto en la medida en que los errores restaurados impidan el uso de algunas características existentes.

Los protocolos cliente/servidor son solo uno de los muchos dominios de compatibilidad posibles. Otro es el formato de datos: ¿el software escribe datos en un almacenamiento permanente? Si es así, los formatos que lee y escribe deben seguir las pautas de compatibilidad prometidas por la política de número de versión. La versión 2.6.0 debe poder leer los archivos escritos por 2.5.4, pero puede actualizar el formato de manera silenciosa a algo que 2.5.4 no pueda leer, porque no se requiere la capacidad de volver atrás en la versión a través de un límite de número menor. Si tu proyecto distribuye librerías de códigos para que otros programas las utilicen, entonces las API también son un dominio de compatibilidad: debes asegurarte de que las reglas de compatibilidad de fuente y de binario estén detalladas de tal manera que el usuario informado nunca deba preguntarse si es seguro o no actualizar. Ella podrá mirar los números y saberlo al instante.

En este sistema, no tienes la oportunidad de comenzar de nuevo hasta que incrementas el número principal. A menudo, esto puede ser un verdadero inconveniente: puede haber funciones que deseas agregar, o protocolos que deseas rediseñar, que simplemente no se pueden hacer mientras se mantiene la compatibilidad. No hay una solución mágica para esto, excepto tratar de diseñar las cosas de forma extensible en primer lugar (un tema que merece su propio libro, y ciertamente fuera del alcance de este). Sin embargo, la publicación de una política de compatibilidad de versiones y su cumplimiento son una parte ineludible de la distribución de software. Una sorpresa desagradable puede alienar a muchos usuarios. La política que acabo de describir es buena en parte porque ya está bastante extendida, pero también porque es fácil de explicar y recordar, incluso para aquellos que aún no están familiarizados con ella.

En general, se entiende que estas reglas no se aplican a las versiones anteriores a la 1.0 (aunque tu política de versión probablemente debería declararlo de manera explícita, solo para que quede claro). Un proyecto que aún está en desarrollo inicial puede liberar 0.1, 0.2, 0.3 y así sucesivamente en secuencia, hasta que esté listo para 1.0, y las diferencias entre esas versiones liberadas pueden ser arbitrariamente grandes. Los números micro en versiones anteriores a la 1.0 son opcionales. Dependiendo de la naturaleza de tu proyecto y las diferencias entre las versiones liberadas, puede ser útil tener 0.1.0, 0.1.1, etc., o no. Las convenciones para los números de liberación anteriores a la 1.0 son bastante flexibles, principalmente porque la gente entiende que las fuertes restricciones de compatibilidad podrían obstaculizar demasiado el desarrollo temprano, y porque los primeros usuarios tienden a perdonar de todos modos.

Recuerda que todos estos requerimientos solo se aplican a este sistema particular de tres componentes. Tu proyecto podría fácilmente crear un sistema de tres componentes diferente, o incluso decidir que no necesita una granularidad fina y, en su lugar, utilizar un sistema de dos componentes. Lo importante es decidir con anticipación, publicar exactamente lo que significan los componentes y atenerse a ellos.

La estrategia Par/Impar

Algunos proyectos utilizan la paridad del componente de número menor para indicar la estabilidad del software: par significa estable, impar significa inestable. Esto se aplica solo al número menor, no a los números principales y micro. Los incrementos en el número micro todavía indican correcciones de errores (no hay nuevas características), y los incrementos en el número principal aún indican grandes cambios, nuevos conjuntos de características, etc.

La ventaja del sistema par/impar, que ha sido utilizado por el proyecto del kernel de Linux entre otros, es que ofrece una forma de liberar nueva funcionalidad para realizar pruebas sin someter a los usuarios de producción a un código potencialmente inestable. La gente puede ver en los números que "2.4.21" se puede instalar en su servidor web en línea, pero que "2.5.1" probablemente debería limitarse a los experimentos de estaciones de trabajo en el hogar. El equipo de desarrollo maneja los informes de errores que provienen de la serie inestable (número menor impar), y cuando las cosas comienzan a calmarse después de un cierto número de versiones liberadas micro en esa serie, incrementan el número menor (lo que lo hace par), restablece el número micro de nuevo a "0" y libera un paquete presumiblemente estable.

Este sistema conserva, o al menos, no está en conflicto con las pautas de compatibilidad dadas anteriormente. Simplemente sobrecarga el número menor con alguna información adicional. Esto obliga a que el número menor se incremente con el doble de frecuencia de lo que sería necesario, pero no hay mucho daño en eso. El sistema par/impar es probablemente mejor para proyectos que tienen ciclos de liberación de versiones muy largos, y que por su naturaleza tienen una alta proporción de usuarios conservadores que valoran la estabilidad por encima de las nuevas características. Sin embargo, no es la única forma de probar nuevas funcionalidades en la naturaleza. “Stabilizing a Release” más adelante en este capítulo describe otro método, quizás más común, de liberar al público código potencialmente inestable, marcado para que las personas tengan una idea de las concesiones de riesgo/beneficio inmediatamente al ver el nombre de la liberación.