Aggiornare React Native da 0.67 a 0.73 senza fermare le release
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:
- Mantenute attivamente — si aggiornano insieme a React Native, senza drammi.
- Mantenute ma indietro — si fissano, e si controlla l’issue tracker prima di ogni passo.
- 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.