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

Tabla de contenidos

Numeración de liberación
Componentes de la numeración de liberación
The Simple Strategy
The Even/Odd Strategy
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 el empaquetado de proyectos Open Source, de cómo liberan su software, y de cómo los patrones de desarrollo globales se organizan en torno a estos fines.

Una de las mayores diferencias entre los proyectos open source 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 Open Source 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; un consistente pero bajo nivel de inconvenientes de fondo son siempre tolerados por el grupo de desarrollo como un todo, 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 para el desarrollo de software libre, por supuesto, pero que es implementado en el software libre de una manera particular. No se puede asumir molestar demasiado a los chicos que trabajar en la carretera ni a la circulación, pero tampoco se puede permitir tener gente dedicada a estar tras los conos naranjas dirigiendo el tráfico con banderas. Así gravitan en torno a procesos que tienen niveles llanos y constantes de esfuerzo de administración, en lugar de altos y bajos. Los voluntarios 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 desarrolladores perdiendo 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 es usalmente la tarea de no-desarrollo mas perceptible que ocurre en paralelo con el desarrollo, por tanto los metodos descritos en las siguientes secciones se orientan principalmente a hablilitar las liberaciones. Sin embargo, nota que esto tambien aplica a otras tareas paralelizables, tales como traducciones e internacionalizaciones, amplios cambios en la API se realizan gradualmente en toda la base de código, etc.

Numeración de liberación

Antes de que hablemos de como hacer una liberación, echemos un vistazo a como nombrar el lanzamiento, lo cual requiere saber que significa en realidad Liberación para los usuarios. Una liberación significa que:

  • Viejos errores se corregieron. Esto es probablemente la unica cosa con la que pueden contar los usuarios como verdadera en cada liberación.

  • Nuevos errores se agregaron. Usualemente tambien se puede contar con esto, excepto algunas veces en el caso de liberaciones de seguridad u otras de unica vez (ver ??? mas 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 fueron cambiadas sutilmente. Tambien los procedimientos de instalación pueden haber cambiado desde la última liberación, aunque uno siempre espera que no.

  • Cambios incompatibles pueden haber sido introducidos, tal que los formatos de datos usados por viejas versiones de software ya no se pueden usar sin utilizar algun tipo de paso de conversión unidireccional (posiblemente manual).

Como puedes ver, no todo esto son buenas cosas. Esto es, el porque usuarios experimientados abordan nuevas liberaciones con cierto temor, especialmente cuando el software es maduro y en su mayoría ya esta haciendo lo que ellos quieren (o pensaron que querian). Incluso la llegada de nuevas características es una bendición mixta, en la que puede significar que el software ahora se comporta de forma inesperada.

El propósito de numerar la liberación, por lo tanto, es doble: obviamente los números deben comunicar sin ambiguedad el orden de las liberaciones (p. ej., mirando a dos números de liberación, uno puede saber cual vino después), pero también debería indicar lo más compactamente posible el grado y naturaleza de los cambios en la liberación.

Todo eso en un número? Bueno, mas o menos, Si. Las estrategias acerca de la numeración de liberación son de las discusiones mas 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 el. Tus usuarios the lo van a agradecer.

Componentes de la numeración de liberación

Esta sección describe detalladamente las convensiones formales de la numeración de liberación, y asume un poco de conocimiento previo. Esto es principalemente una referencia. Si ya estas familiarizado con estas convensiones, puedes saltarte esta sección.

Los números de la liberación son grupos de digitos 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 mas famoso es el kernel de Linux con su secuencia "0.95", "0.96"... "0.99" que conduce a Linux 1.0, pero la convension de que los puntos no son decimales esta firmemente establecida y deberí ser considerada como estándard. No hay límite en los componentes de los números (porciones de digitos que no contienen puntos), pero la mayoría de los proyectos no van mas allá de tres o cuatro. Las razones de porque se aclararan mas adelante.

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

Scanley 2.3.0 (Alpha)
Singer 5.11.4 (Beta)

Un clasificador como Alpha o Beta signigica que esta liberación precede a una liberación futura que va a tener el mismo número sin el clasificador. Así, "2.3.0 (Alpha)" conduce eventualmente a "2.3.0". Con el fin de permitir varias liberaciones de una sola vez, los clasificadores en si mismos pueden tener meta-clasificadores. Por ejemplo, aqui una serie de liberaciones en el orden en el que estaran disponibles disponibles al público:

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

Nota que cuando tiene el clasificador "Alpha", Scanley "2.3" is written as "2.3.0". The two numbers are equivalent—trailing all-zero components can always be dropped for brevity—but when a qualifier is present, brevity is out the window anyway, so one might as well go for completeness instead.

Other qualifiers in semi-regular use include "Stable", "Unstable", "Development", and "RC" (for "Release Candidate"). The most widely used ones are still "Alpha" and "Beta", with "RC" running a close third place, but note that "RC" always includes a numeric meta-qualifier. That is, you don't release "Scanley 2.3.0 (RC)", you release "Scanley 2.3.0 (RC 1)", followed by RC2, etc.

Those three labels, "Alpha", "Beta", and "RC", are pretty widely known now, and I don't recommend using any of the others, even though the others might at first glance seem like better choices because they are normal words, not jargon. But people who install software from releases are already familiar with the big three, and there's no reason to do things gratuitously differently from the way everyone else does them.

Although the dots in release numbers are not decimal points, they do indicate place-value significance. All "0.X.Y" releases precede "1.0" (which is equivalent to "1.0.0", of course). "3.14.158" immediately precedes "3.14.159", and non-immediately precedes "3.14.160" as well as "3.15.anything", and so.

A consistent release numbering policy enables a user to look at two release numbers for the same piece of software and tell, just from the numbers, the important differences between those two releases. In a typical three-component system, the first component is the major number, the second is the minor number, and the third is the micro number. For example, release "2.10.17" is the seventeenth micro release in the tenth minor release line within the second major release series. The words "line" and "series" are used informally here, but they mean what one would expect. A major series is simply all the releases that share the same major number, and a minor series (or minor line) consists of all the releases that share the same minor and major number. That is, "2.4.0" and "3.4.1" are not in the same minor series, even though they both have "4" for their minor number; on the other hand, "2.4.0" and "2.4.2" are in the same minor line, though they are not adjacent if "2.4.1" was released between them.

The meanings of these numbers are exactly what you'd expect: an increment of the major number indicates that major changes happened; an increment of the minor number indicates minor changes; and an increment of the micro number indicates really trivial changes. Some projects add a fourth component, usually called the patch number, for especially fine-grained control over the differences between their releases (confusingly, other projects use "patch" as a synonym for "micro" in a three-component system). There are also projects that use the last component as a build number, incremented every time the software is built and representing no change other than that build. This helps the project link every bug report with a specific build, and is probably most useful when binary packages are the default method of distribution.

Although there are many different conventions for how many components to use, and what the components mean, the differences tend to be minor—you get a little leeway, but not a lot. The next two sections discuss some of the most widely used conventions.

The Simple Strategy

Most projects have rules about what kinds of changes are allowed into a release if one is only incrementing the micro number, different rules for the minor number, and still different ones for the major number. There is no set standard for these rules yet, but here I will describe a policy that has been used successfully by multiple projects. You may want to just adopt this policy in your own project, but even if you don't, it's still a good example of the kind of information release numbers should convey. This policy is adapted from the numbering system used by the APR project, see http://apr.apache.org/versioning.html.

  1. Changes to the micro number only (that is, changes within the same minor line) must be both forward- and backward-compatible. That is, the changes should be bug fixes only, or very small enhancements to existing features. New features should not be introduced in a micro release.

  2. Changes to the minor number (that is, within the same major line) must be backward-compatible, but not necessarily forward-compatible. It's normal to introduce new features in a minor release, but usually not too many new features at once.

  3. Changes to the major number mark compatibility boundaries. A new major release can be forward- and backward-incompatible. A major release is expected to have new features, and may even have entire new feature sets.

What backward-compatible and forward-compatible mean, exactly, depends on what your software does, but in context they are usually not open to much interpretation. For example, if your project is a client/server application, then "backward-compatible" means that upgrading the server to 2.6.0 should not cause any existing 2.5.4 clients to lose functionality or behave differently than they did before (except for bugs that were fixed, of course). On the other hand, upgrading one of those clients to 2.6.0, along with the server, might make new functionality available for that client, functionality that 2.5.4 clients don't know how to take advantage of. If that happens, then the upgrade is not "forward-compatible": clearly you can't now downgrade that client back to 2.5.4 and keep all the functionality it had at 2.6.0, since some of that functionality was new in 2.6.0.

This is why micro releases are essentially for bug fixes only. They must remain compatible in both directions: if you upgrade from 2.5.3 to 2.5.4, then change your mind and downgrade back to 2.5.3, no functionality should be lost. Of course, the bugs fixed in 2.5.4 would reappear after the downgrade, but you wouldn't lose any features, except insofar as the restored bugs prevent the use of some existing features.

Client/server protocols are just one of many possible compatibility domains. Another is data formats: does the software write data to permanent storage? If so, the formats it reads and writes need to follow the compatibility guidelines promised by the release number policy. Version 2.6.0 needs to be able to read the files written by 2.5.4, but may silently upgrade the format to something that 2.5.4 cannot read, because the ability to downgrade is not required across a minor number boundary. If your project distributes code libraries for other programs to use, then APIs are a compatibility domain too: you must make sure that source and binary compatibility rules are spelled out in such a way that the informed user need never wonder whether or not it's safe to upgrade in place. She will be able to look at the numbers and know instantly.

In this system, you don't get a chance for a fresh start until you increment the major number. This can often be a real inconvenience: there may be features you wish to add, or protocols that you wish to redesign, that simply cannot be done while maintaining compatibility. There's no magic solution to this, except to try to design things in an extensible way in the first place (a topic easily worth its own book, and certainly outside the scope of this one). But publishing a release compatibility policy, and adhering to it, is an inescapable part of distributing software. One nasty surprise can alienate a lot of users. The policy just described is good partly because it's already quite widespread, but also because it's easy to explain and to remember, even for those not already familiar with it.

It is generally understood that these rules do not apply to pre-1.0 releases (although your release policy should probably state so explicitly, just to be clear). A project that is still in initial development can release 0.1, 0.2, 0.3, and so on in sequence, until it's ready for 1.0, and the differences between those releases can be arbitrarily large. Micro numbers in pre-1.0 releases are optional. Depending on the nature of your project and the differences between the releases, you might find it useful to have 0.1.0, 0.1.1, etc., or you might not. Conventions for pre-1.0 release numbers are fairly loose, mainly because people understand that strong compatibility constraints would hamper early development too much, and because early adopters tend to be forgiving anyway.

Remember that all these injunctions only apply to this particular three-component system. Your project could easily come up with a different three-component system, or even decide it doesn't need such fine granularity and use a two-component system instead. The important thing is to decide early, publish exactly what the components mean, and stick to it.

The Even/Odd Strategy

Some projects use the parity of the minor number component to indicate the stability of the software: even means stable, odd means unstable. This applies only to the minor number, not the major and micro numbers. Increments in the micro number still indicate bug fixes (no new features), and increments in the major number still indicate big changes, new feature sets, etc.

The advantage of the even/odd system, which has been used by the Linux kernel project among others, is that it offers a way to release new functionality for testing without subjecting production users to potentially unstable code. People can see from the numbers that "2.4.21" is okay to install on their live web server, but that "2.5.1" should probably stay confined to home workstation experiments. The development team handles the bug reports that come in from the unstable (odd-minor-numbered) series, and when things start to settle down after some number of micro releases in that series, they increment the minor number (thus making it even), reset the micro number back to "0", and release a presumably stable package.

This system preserves, or at least, does not conflict with, the compatibility guidelines given earlier. It simply overloads the minor number with some extra information. This forces the minor number to be incremented about twice as often as would otherwise be necessary, but there's no great harm in that. The even/odd system is probably best for projects that have very long release cycles, and which by their nature have a high proportion of conservative users who value stability above new features. It is not the only way to get new functionality tested in the wild, however. “Stabilizing a Release” later in this chapter describes another, perhaps more common, method of releasing potentially unstable code to the public, marked so that people have an idea of the risk/benefit trade-offs immediately on seeing the release's name.