Actualitzar més de 23.000 paquets de R a la vegada i que res es trenqui: Així ho fa CRAN

Si fas servir npm, PyPI, crates, Composer o Maven en el teu dia a dia i no has fet servir mai R, això t’interessa.

Si ja has fet servir R alguna vegada, segurament has vist que instal·les un paquet, actualitzes dependències i tot continua funcionant.

Sembla obvi que hagi de ser així, oi? Doncs atura’t. Això que sembla tan normal és en realitat extraordinari i és cosa de CRAN.

Imagina’t per un segon que vols actualitzar una llibreria en el teu projecte i fas una cosa com:

$ pip3 install numpy --upgrade

No funciona i proves:

$ pip3 install numpy --upgrade --ignore-installed

Tampoc. Hi tornes amb:

$ uv lock --upgrade-package "numpy==2.4.0"

A mi em faria por fer-ho a producció sense provar-ho abans. Perquè una actualització mal gestionada pot desencadenar dependències trencades i fer que el projecte falli per canvis en funcions o mètodes de la nova versió.

Quan treballo amb paquets de CRAN a R, tinc la tranquil·litat de saber que la instal·lació de l’última versió de qualsevol dels 23.721 que hi ha a CRAN em funcionarà (a dia 2026-05-21).

No és extraordinari?

Doncs et vull explicar com funciona CRAN per fer-ho possible i reflexionar sobre els seus pros i contres.

Canvi de mentalitat: De repositori a direcció paternalista

CRAN (Comprehensive R Archive Network) va néixer el 1997 amb la mentalitat de servir com a entorn de treball per a estadístics. Un tipus d’usuari a qui preferiries no demanar que resolgui problemes tècnics en sistemes Linux, Windows, macOS, Solaris, etc.

Perl va ser força popular entre 1995 i 2005. El 1995 es va publicar CPAN (Comprehensive Perl Archive Network), un monorepositori inspirat en CTAN (Comprehensive TeX Archive Network). Un altre monorepositori publicat el 1992.

“…Un Anell per manar a tots, Un per trobar-los,
Un Anell per reunir-los i, en les Tenebres
tenir tots lligats a Mórdor on s’estén l’Ombra.”
– La Germandat de l’Anell. Capítol 2: «L’ombra del passat»

Per a scripts personals, eines internes o experiments, plataformes com GitHub, GitLab, Codeberg o similars són perfectes: tens llibertat absoluta, puges el codi i fas un push. Però si tota la seva distribució fos així, seria «la llei de la selva».

En repositoris com PyPI, npm, crates o similar, registrar un paquet no és gaire diferent: et registres, el puges i ja està. L’autor podria esborrar el repositori o canviar les funcions o mètodes sense avisar, o que algun col·laborador li hagi colat un codi maliciós que ningú més hagi revisat. Això és un problema greu si altres paquets l’utilitzaven. I tot fa pensar que amb els assistents de codi d’IA passarà cada vegada més sovint.

Vaig crear un paquet helloworld només amb el propòsit de fer-lo servir en un procés de CI que volia provar. A PyPI o npm ningú pregunta ni revisa. A CRAN, em van rebutjar perquè no aportava valor real als seus usuaris (Tenien raó).

En lloc de tenir un magatzem de paquets aïllats, CRAN tracta tot l’ecosistema com si fos un únic repositori gegant interconnectat.

A CRAN hi ha una revisió per a cada enviament. Aquesta “burocràcia” és un filtre de qualitat. Tot paquet que arriba a la cua d’enviament de CRAN passa per:

  • Llistes d’espera (Se’n pot fer seguiment a través de cransays).
  • Es fan comprovacions automàtiques en múltiples sistemes operatius i versions de R.
  • Revisió manual per part de voluntaris de l’equip de CRAN.
  • Verificació de dependències inverses.
  • Compliment estricte de la CRAN Repository Policy.
  • I segur que em deixo coses.

Aquest procés garanteix que, quan instal·les un paquet de CRAN, sàpigues que algú l’ha mirat abans que tu.

Que CRAN sigui gestionat per un equip de voluntaris principalment via llistes de correu electrònic, té el seu encant.

Gestió de dependències inverses

En altres llenguatges de programació és habitual que cada paquet declari qualsevol rang de versions. Llavors, per resoldre dependències, cal fer malabars per trobar una combinació compatible (i sense garantia que sigui fins i tot possible).

CRAN té regles molt estrictes de compatibilitat cap enrere: els paquets han de funcionar amb la versió actual de R i amb les versions especificades a les seves dependències. La immensa majoria especifiquen límits inferiors (>= x.y.z) i no especifiquen versions estrictes (== x.y.z).

Aquesta mentalitat de direcció paternalista permet a l’usuari d’R actualitzar sense tenir por de trencar res.

  • A Debian/Ubuntu hi ha un procés d’auto-removal en el que et poden arxivar el paquet, si detecten que deixa de funcionar per alguna dependència trencada (entre altres coses).
  • A CRAN va un pas més enllà. Si el procés “R CMD check” dona algun error (ERROR) o advertència (WARNING), es rebutja automàticament de la cua. Si es detecta una fallada en un tercer, l’actualització es frena. No pots actualitzar el teu paquet per haver trencat l’ús que en fan altres paquets.

Et deus estar preguntant: Com? Què? Eh?

És el que s’anomena la política de dependències inverses, i és el pilar de l’estabilitat de l’ecosistema. Quan un autor vol pujar una actualització, has de comprovar que aquesta nova versió no trenqui cap dels paquets que en depenen.

Això significa que si la teva actualització fa que el paquet d’un senyor d’Andorra, a qui no coneixes de res, deixi de passar els tests, CRAN no acceptarà la teva actualització fins que reverteixis el teu codi per mantenir la compatibilitat cap enrere o bé, contactis amb l’altre autor perquè actualitzi el seu paquet simultàniament.

Aquest procés garanteix que el catàleg actiu estigui 100% funcional. No hi ha paquets «zombis» que es mantinguin a la llista principal malgrat estar trencats.

Ara bé, el mantenidor del paquet paga el preu (en temps, revisions, comunicacions, controls…) perquè l’usuari final tingui un camí lliure d’obstacles.

Un cas concret. Els autors del paquet {glmnet}, molt popular, van haver de coordinar una migració amb més de 150 dependències inverses en una sola actualització.

És una feinada “ser” a CRAN

CRAN funciona com un repositori de desenvolupament continu: quan es publica una nova versió d’un paquet, l’anterior no s’esborra, sinó que es mou a l’àrea d’arxiu. Això té dues conseqüències clau:

  • Quan fas `install.packages()` obtens la versió més recent que ha passat tots els controls de CRAN.
  • Si tens tots els paquets de CRAN actualitzats i una cosa et deixa de funcionar, és perquè et cal actualitzar el teu codi a les noves versions.

L’historial és accessible: Si necessites una versió antiga per reproductibilitat, pots accedir-hi programàticament via l’arxiu o amb eines com {renv} o {rix}, sigui amb la versió concreta o amb l’última versió publicada en una data “congelada”.

Com pots suposar, en comparació, és una feinada pujar un nou paquet a CRAN. Però no només això, també és una feinada ser-hi. O sigui, mantenir-s’hi.

Sóc contribuïdor d’alguns paquets i recentment em van acceptar un paquet molt petit anomenat {gtakeout}.

Per tant, si ho he fet jo, això demostra que ho pot fer tothom. Tot i que pot ser frustrant, és el que garanteix la qualitat de l’ecosistema. Hi ha coses complicades que s’aprenen fent-les una vegada i una altra.

No tot és CRAN

CRAN té una política molt estricta, gairebé draconiana: està prohibit descarregar fitxers o dependències de tercers d’Internet durant el procés d’instal·lació de l’usuari (tret de casos excepcionals molt pactats). Tot ha d’estar contingut en el paquet.

Això significa que els autors que utilitzen llibreries externes no poden fer que els seus paquets les descarreguin. Per exemple, com que no poden descarregar les llibreries de Rust amb `cargo fetch`, els desenvolupadors es veuen obligats a incloure el codi de les dependències externes dins del mateix paquet d’R i a documentar manualment cada una de les llicències del codi que inclouen.

A més, com que CRAN també imposa límits estrictes de mida, hi ha autors que per distribuir més enllà d’un repositori git, prefereixen publicar els seus paquets en repositoris alternatius.

Si vols que el teu codi sigui una eina fiable per a la comunitat, necessites un repositori més formal. Aquí és on entren CRAN, Bioconductor, Multiverse o, en l’àmbit corporatiu, un repositori privat estil CRAN gestionat internament (Posit Package Manager, drat, etc)

Per acabar, una reflexió i una petició

La reflexió: CRAN és anti-marketing.

Sí, més maldecaps pels desenvolupadors significa uns números menys brillants de volum de paquets disponibles, però trobo que val la pena tenir un espai on es prioritzi la responsabilitat davant l’usuari. Això dona lloc a un ecosistema o entorn de treball que progressa potser més lentament però més col·laborativament.

Diuen que R és un llenguatge peculiar per la seva expressivitat, però potser ho és més per la seva cultura de comunitat pensada pels seus usuaris.

La petició: T’animo a provar R avui mateix.

Instal·la’l i prova’l ara mateix. Encara que només sigui per dir-te el resultat de sumar 1+1. Ja em diràs què tal.

Deixa un comentari

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *

This site uses Akismet to reduce spam. Learn how your comment data is processed.