Vai al contenuto
Mario Norato

Aggiornare React Native da 0.67 a 0.73 senza fermare le release

3 min di lettura

Anche in inglese →

Esiste una versione di questo articolo che è un elenco di comandi npm install. Non è questa, perché i comandi non sono mai stati la parte difficile.

La situazione: un’app Bitcoin consumer, viva su entrambi gli store, su React Native 0.67. Sei versioni minori indietro. Nessuno avrebbe concesso un feature freeze per un aggiornamento di versione, e giustamente — l’app generava fatturato e la roadmap era piena.

Perché non puoi saltare direttamente alla versione finale

Il piano ovvio è passare da 0.67 a 0.73 in un unico branch. Fallisce per un motivo che è facile sottovalutare: quando l’app si rompe, non hai idea di quale delle sei versioni l’abbia rotta.

Ogni release minore di React Native sposta qualcosa di strutturale. Tra la 0.67 e la 0.73 attraversi Hermes che diventa il motore di default, i cambiamenti al plugin Gradle di Android, un nuovo resolver di Metro e una lunga coda di dipendenze native che si muovono. Se le fai atterrare insieme, ogni bug diventa una bisect su sei release notes contemporaneamente.

Quindi: una versione minore per branch, ognuna mergiata e rilasciata ai tester interni prima di iniziare la successiva.

# Una versione alla volta, leggendo ogni riga del diff
npx react-native upgrade 0.68.0

Il React Native Upgrade Helper mostra il diff tra due versioni qualsiasi del progetto template. Trattalo come fonte di verità al posto del codemod, soprattutto per i file nativi: android/app/build.gradle e il Podfile iOS richiedono quasi sempre una mano umana.

L’audit delle dipendenze viene prima di tutto

Prima di toccare la versione del framework ho passato in rassegna il package.json rispondendo a una domanda per riga: questa libreria ha una release che supporta la versione verso cui mi sto muovendo?

Ne sono uscite tre categorie:

  1. Mantenute attivamente — si aggiornano insieme a React Native, senza drammi.
  2. Mantenute ma indietro — si fissano, e si controlla l’issue tracker prima di ogni passo.
  3. Abbandonate — si sostituiscono prima della migrazione, non durante.

È la terza categoria a mangiarsi il calendario. Un modulo nativo morto scoperto a metà di un aggiornamento significa che stai facendo due migrazioni nello stesso branch, cioè esattamente la cosa che questo approccio esiste per evitare.

Sono stati i test a renderlo un non-evento

Il lavoro sulla copertura era arrivato prima, per motivi indipendenti: quando è iniziato l’aggiornamento c’era una suite vera alle spalle, con Detox a coprire i flussi che toccano i soldi. Si è rivelato la ragione per cui un salto di sei versioni è stato routine invece che terrore.

L’aggiornamento di un framework rompe il codice in punti dove a nessuno viene in mente di cliccare. La formattazione dei numeri cambia. Una FlatList smette di scorrere su un certo API level di Android. Una data viene renderizzata con un giorno di scarto in un fuso orario. Queste cose non le trovi aprendo l’app e guardandola. Le trovi perché un test che passava da due anni improvvisamente non passa più.

Se la tua copertura è sottile, investi lì per primo. Un aggiornamento senza rete non è una migrazione, è una scommessa.

Cosa farei diversamente

Aggiornare in continuo. Il motivo per cui da 0.67 a 0.73 è diventato un progetto è che per diciotto mesi nessuno aveva trattato la versione del framework come manutenzione. Una versione minore ogni due mesi, assorbita nel normale lavoro di sprint, non diventa mai un progetto.

Il costo di stare aggiornati è piccolo e costante. Il costo di rimettersi in pari è grande e arriva tutto insieme, di solito nel momento peggiore.