Donat un nombre de versió MAJOR.MINOR.PATCH, heu d’incrementar:
Es poden afegir etiquetes addicionals per a versions preliminars i metadades de compilació com a extensió del format MAJOR.MINOR.PATCH.
Al món de la gestió del programari hi ha un lloc temut anomenat “l’infern deles dependències” (de l’anglès “dependency hell”). Com més gran creixi el vostresistema i més components hi integreu, més probable serà que us trobeu, algundia, en aquest abisme de desesperació.
En sistemes amb moltes dependències, publicar la versió d’un nou component potesdevenir ràpidament un malson. Si les regles de dependència són massaestrictes, us podeu trobar en el perill de blocar les vostres versions, (laincapacitat d’actualitzar un component sense haver de publicar una novaversió de cada component que en depèn d’ell). En canvi, si les regles dedependència són massa toves, inevitablement patireu la promiscuïtat de versions(mantenir una compatibilitat amb més versions futures del que seria raonable).L’infern de les dependències és quan el bloqueig o la promiscuïtat de versionsus impedeixen avançar el vostre projecte de manera fàcil i sense riscos.
Com a solució a aquest problema, proposo un conjunt de regles i requisitssenzills que dicten com s’assignen i incrementen els nombres de versions.Aquestes regles es basen, però no es limiten necessàriament, en pràctiquesgeneralitzades en programari privat i lliure. Perquè aquest sistema funcioni,primer heu de declarar una API pública. Pot consistir en un document o en lesnormes imposades pel propi codi. Tanmateix, és important que aquesta APIsigui clara i precisa. Un cop l’hàgiu enllestida, comuniqueu els canvis quehi feu amb increments específics en el nombre de versió. Considerant el formatde la versió X.Y.Z (Major.Minor.Patch): quan les correccions o pedaços noafectin l’API s’ha d’incrementar la versió de correcció (‘patch’), quan s’hiafegeixin canvis i/o millores que tampoc afectin l’API s’ha d’incrementar la versiómenor (‘minor’), i quan els canvis afectin la compatibilitat de l’API amb versionsanteriors s’ha d’incrementar la versió principal (‘major’).
Jo anomeno aquest sistema “gestió semàntica de versions”. Amb aquest sistema,els nombres de versió i la manera com canvien donen sentit al codi subjacenti a tot allò que s’ha modificat d’una versió a una altra.
Les paraules clau “HA DE” (“MUST”, “REQUIRED” i “SHALL”), “NO HA DE” (“MUSTNOT” i “SHALL NOT”), “HAURIA DE” (“SHOULD” i “RECOMMENDED”) i “POT” (“MAY i“OPTIONAL”) d’aquest document han de ser interpretades tal i com es descriuenen el documentRFC 2119.
Tot programari que utilitzi la gestió semàntica de versions HA DE declararuna API pública. Aquesta API es pot declarar en el mateix codi o en un document.En qualsevol cas, ha de ser precisa i comprensible.
Un nombre de versió normal HA DE tenir la forma X.Y.Z on X, Y i Z representennombres enters no negatius, i NO HAN DE ser prefixats amb zeros. X represental’identificador de versió principal (‘major’), Y representa l’identificador deversió menor (‘minor’) i Z l’identificador de versió de correcció (‘patch’). Cadaelement HA DE ser augmentat numèricament. Per exemple: 1.9.0 -> 1.10.0 -> 1.11.0.
Un cop es publica una nova versió d’un component, el contingut d’aquesta versióNO HA DE ser modificat. Qualsevol canvi HA DE ser publicat en una nova versió.
L’identificador de versió principal (‘major’) a zero (0.y.z) és per aldesenvolupament inicial. Vol dir que qualsevol cosa pot canviar en qualsevolmoment. En aquest punt, l’API pública no hauria de considerar-se estable.
La versió 1.0.0 defineix l’API pública. La forma en què el nombre de versiós’incrementi després d’aquesta publicació dependrà d’aquesta API pública ide les seves evolucions.
L’identificador de versió de correcció (‘patch’) Z (x.y.Z | x > 0) HA DE serincrementat si només s’introdueixen correccions compatibles amb les versionsanteriors. Una correcció es defineix com un canvi intern que corregeix uncomportament incorrecte.
L’identificador de versió menor (‘minor’) Y (x.Y.z | x > 0) HA DE serincrementat si s’introdueixen a l’API pública noves funcionalitats compatiblesamb versions anteriors. També HA DE ser incrementat si es tracta d’una funcionalitatmarcada com a obsoleta a l’API pública. Es POT incrementar si s’introdueixen novesfuncionalitats o millores substancials en el codi privat. POT incloure alhorapetites correccions. L’identificador de versió de correcció (‘patch’)s’HA DE posar a 0 quan s’incrementi l’identificador de versió menor (‘minor’).
L’identificador de versió principal (‘major’) X (X.y.z | X > 0) HA DE serincrementat si s’introdueixen canvis no compatibles amb versions anteriors del’API pública. POT incloure alhora petits canvis i correccions. Els identificadorsde versió menor (‘minor’) i de correcció (‘patch’) s’HAN DE posar a 0 quans’incrementi l’identificador de versió principal (‘major’).
Es POT marcar una versió de pre-llançament afegint un guió i una sèried’identificadors separats per punts immediatament després de l’identificadorde versió de correcció (‘patch’). Aquests identificadors HAN DE consistirúnicament en guions i caràcters ASCII alfanumèrics [0-9A-Za-z-]. Aquestsidentificadors NO HAN D’estar buits. Els identificadors numèrics NO HAN DEser prefixats amb zeros. Les versions de pre-llançament precedeixen la versiónormal associada. Una versió de pre-llançament indica que la versióno és estable i no necessàriament compleix els requisits de compatibilitatassociat a una versió normal. Exemples: 1.0.0-alpha, 1.0.0-alpha.1,1.0.0-0.3.7, 1.0.0-x.7.z.92.
Les metadades de compilació es PODEN marcar afegint un signe més i una sèried’identificadors separats per punts immediatament després de l’identificadorde versió de correcció (‘patch’) o de pre-llançament. Aquests identificadors HAN DEconsistir únicament en guions i caràcters ASCII alfanumèrics [0-9A-Za-z-]. Aquestsidentificadors NO HAN D’estar buits. Les metadades de la compilació HAURIEN DE serignorades quan es determini l’ordre de les versions. Per tant, dues versions quedifereixen només per la seva informació de compilació tenen la mateixa prioritat.Exemples: 1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85.
La prioritat o precedència defineix com s’ordenen les versions entre sí. Laprioritat HA DE ser calculada separant els identificadors de la versió entreprincipal, menor, correcció i pre-llançament, seguint aquest ordre. (La informacióde compilació no compta durant la comparació). La prioritat es determina per laprimera diferència que apareix a la comparació de cadascun d’aquests identificadorsen l’ordre: principal, menor i correcció. Aquests identificadors sempre es comparennumèricament. Exemple: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1. Quan els identificadorsprincipal, menor i correcció són idèntics, una versió de pre-llançament té menorprioritat que una versió normal. Exemple: 1.0.0-alpha < 1.0.0. La prioritat dedues versions de pre-llançament amb els mateixos identificadors principal, menori correcció HA DE ser determinada mitjançant la comparació de cadascun delsidentificadors separats per un punt, d’esquerra a dreta fins que es trobi ladiferència, de la següent manera: els identificadors compostos només de nombreses comparen numèricament, i els identificadors que contenen lletres o guions escomparen en ordre ASCII. Els identificadors numèrics sempre són menys importantsque els identificadors no numèrics. Un conjunt més llarg d’identificadors depre-llançament té major prioritat sobre un conjunt més curt, si tots els identificadorsanteriors són idèntics. Exemple: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta <1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.
No és pas una idea nova o revolucionària. De fet, probablement ja esteu fentalguna cosa semblant. El problema és que això ‘semblant’ no és prou bo. Senseel compliment d’un mètode els nombres de versió no es poden utilitzar per lagestió de dependències. Pel sol fet de donar un nom i una definició clares ales idees que s’han mostrat a dalt, es fa fàcil comunicar les vostresintencions als usuaris del vostre programari. Un cop aquestes intencions sónclares i flexibles (però no gaire flexibles) es pot dur a terme l’especificacióde dependències.
Un senzill exemple pot mostrar com la gestió semàntica de versions pot fer quel’infern de les dependències sigui una cosa del passat. Considera una llibreriaanomenada “CamióDeBombers”. Requereix un component anomenat “Escala”, el qualtracte les versions de forma semàntica. Quan es crea la llibreria CamióDeBombers,l’Escala és a la versió 3.1.0. Atès que CamióDeBombers utilitza funcions que esvan introduir a la versió 3.1.0, podeu especificar, sense cap risc, unadependència de l’Escala superior o igual a 3.1.0 però inferior a 4.0.0. Ara,quan les versions 3.1.1 i 3.2.0 de l’Escala estan disponibles, podeu publicar-lesal vostre sistema de gestió de dependències i sabreu que seran compatibles ambel programari existent que en depèn d’elles.
Com a desenvolupador responsable, voldreu verificar evidentment que qualsevolactualització del component funciona tal i com s’anuncia. El món real és unmerder; no hi ha res que puguem fer excepte estar a l’aguait. El que podeu fer,però, és deixar que la gestió semàntica de versions us proporcioni una manerasaludable de publicar i actualitzar els vostres components, sense haverd’implementar noves versions de components dependents, estalviant-vos temps iesforç.
Si tot això us sona bé, tot el que heu de fer per començar a utilitzar la gestiósemàntica de la versions és declarar que ho feu i llavors seguiu les regles.Afegiu un enllaç a aquest lloc web al vostre fitxer README i així altres podranconèixer les regles i beneficiar-se’n.
El més fàcil de fer és començar els teus desenvolupaments amb la versió 0.1.0 i,a continuació, incrementar l’identificador de versió menor a cada nova publicació.
Si el vostre programari s’utilitza en un entorn de producció, ja hauríeu d’estara la versió 1.0.0. Si teniu una API estable a partir de la qual els usuaris hancomençat a dependre’n, ja hauríeu d’estar a la versió 1.0.0. Si us amoïna molt lacompatibilitat amb versions anteriors, ja hauríeu d’estar a la versió 1.0.0.
La versió principal (‘major’) a 0 es fa precisament per tenir un desenvolupamentràpid. Si canvieu l’API cada dia hauríeu de ser a la versió 0.y.z o en una brancade desenvolupament independent que acabarà sent la nova versió principal.
Es tracta d’un desenvolupament responsable i d’una anticipació. Els canvisincompatibles no s’han d’introduir a la lleugera en un programari amb ungran nombre de codi font depenent. El cost d’una actualització a una nova versiópot ser important. La necessitat d’augmentar la versió principal per publicarels canvis que no siguin compatibles amb versions anteriors, significa quehaureu mesurat les implicacions dels canvis i avaluada la relació entre el seucost i els seus beneficis.
És la vostra responsabilitat com a desenvolupador professional documentarcorrectament el programari que altres usuaris pensen utilitzar. Gestionar lacomplexitat d’un programari és una part immensament important per mantenirun projecte eficient, i es fa difícil de fer quan ningú no sap com utilitzarel vostre programari, o quins són els mètodes adequats per cridar. A la llargala gestió semàntica de versions, i els esforços en la conservació d’unaAPI pública ben definida permetrà que tots puguem avançar sense problemes.
Tan bon punt us adoneu que heu trencat la gestió semàntica de la vostra versió,corregiu el problema i publiqueu una nova versió menor que restauri lacompatibilitat amb versions anteriors. Fins i tot en aquestes circumstàncies,és inacceptable modificar una versió ja publicada. Actualitzeu, si cal, ladocumentació informant sobre la versió defectuosa i informeu als vostres usuarisd’aquest problema.
Això es pot considerar compatible ja que no afecta l’API pública. El programarique depèn de les mateixes dependències que el vostre component hauria de tenirla seva pròpia especificació de dependència i l’autor també s’adonarà dequalsevol conflicte. Per determinar si el canvi és una correcció o un canvimenor, heu de preguntar-vos si heu actualitzat les vostres dependències percorregir un error o per introduir una nova característica. En general, esperariaafegir codi nou en la segona opció, cosa que implica òbviament un increment del’identificador de versió menor.
Feu servir el seny. Si teniu un gran públic que es veurà afectat dràsticament pelcanvi de comportament de l’API pública respecte el que hauria de fer, llavors potser preferible llançar una nova versió principal (‘major’), encara que aquestaversió es pugui considerar una versió de correcció. Recordeu, la gestió semànticade versions és bàsicament per transmetre significats en la forma en què canvia elnombre de versió. Si aquests canvis són importants per als vostres usuaris,utilitzeu els nombres de versió per informar-los.
La obsolescència de funcionalitats existents és una part normal del desenvolupamentdel programari i molt sovint es fa necessari per avançar. Quan desaproveuuna part de la vostra API pública, heu de fer dues coses: (1) actualitzar ladocumentació per informar els usuaris del canvi, (2) publicar una nova versiómenor amb la part desaprovada. Abans d’eliminar completament la funcionalitaten un nou llançament de versió important (‘major’), hauria d’haver almenys unaversió menor que contingui la desaprovació perquè els usuaris puguin transitarsense problemes cap a la nova API.
No, però feu servir el sentit comú. Per exemple, un nombre de versió de 255 caràctersprobablement sigui excessiu. A més, alguns sistemes poden imposar les seves pròpieslimitacions en aquesta mida.
L’especificació de la gestió semàntica de versions està escrita perTomPreston-Werner, inventor de Gravatars icofundador de GitHub.
Traducció d’aquest document a càrrec de:
Si voleu deixar comentaris, si us plauobre un tiquet aGitHub.