Introduzione

Se state iniziando lo sviluppo di un nuovo prodotto, potreste trovarvi nella necessità di avere sia un’applicazione mobile che una web. In questo post scopriremo come farlo in modo efficiente!

Il problema

La condivisione della logica di business tra l’applicazione mobile e quella web del vostro prodotto può essere una scelta utile per migliorare l’esecuzione e la manutenibilità. Tuttavia, condividere la logica di business tra piattaforme diverse non è sempre facile, perché richiede un’attenta considerazione di diversi fattori (di cui parleremo più avanti).

In questo articolo faremo degli esempi di logica condivisa tra un’applicazione React e un’applicazione mobile React Native utilizzando l’approccio monorepo. Inoltre, per gestire meglio il nostro monorepo, useremo Nx sviluppato da Nrwl!

https://media.giphy.com/media/3o7btNa0RUYa5E7iiQ/giphy.gif

Approccio monorepo

Negli ultimi anni, i monorepo sono diventati una scelta popolare per la gestione di grandi codebase. Un monorepo è essenzialmente un singolo repository che contiene tutti i moduli di un progetto e le loro dipendenze. La sua adozione è dovuta a diversi fattori:

  • Gli sviluppatori tendono a preferire il lavoro in un unico repository rispetto ad averne tanti più piccoli. Questo approccio riduce l’overhead del context switch tra i diversi progetti e minimizza i conflitti quando gli sviluppatori collaborano alle modifiche su più repository contemporaneamente.
  • È più facile trovare i file quando tutto è riunito in un unico posto (questo può essere particolarmente utile se avete grandi team con decine o centinaia di ingegneri).
  • L’uso di un unico sistema di source versioning (ad esempio git) significa che non c’è bisogno di complicate strategie di branching o di altre soluzioni per assicurarsi che il vostro team non si ritrovi con decine di copie della stessa codebase sparse in diversi repository: la vostra intera codebase vive in un unico posto!

Cos’è Nx?

Nx è un sistema di compilazione intelligente, veloce ed estensibile, con potenti integrazioni ed un supporto ai monorepo di prima classe.

Supporta ambienti Javascript/Typescript, fornisce cache nel cloud e build veloci.

Tutti i moduli in un unico repository? 🤔

Sì, so che può sembrare un tabù, ma analizziamo i pro per il nostro esempio specifico:

  • abbiamo un singolo file package.json, quindi Nx gestirà le dipendenze condivise tra più pacchetti.
  • possiamo centralizzare il processo di linting, costruzione, test e rilascio.
  • è conveniente coordinare le modifiche tra più pacchetti. Per esempio, se abbiamo un pacchetto che dipende da altri due, avremo bisogno di un solo comando per aggiornarli entrambi e non dovremo aprire due richieste di pull e disturbare metà del team.

Inoltre, ci sono diversi esempi di monorepo famosi, vediamone alcuni:

  • Babel: un popolare compilatore JavaScript usato nello sviluppo web. Un monorepo contiene il progetto completo e tutti i suoi plug-in.
  • Lo stesso React è un monorepo.

Quali sono i contro?

Uno dei maggiori svantaggi di questo approccio è che può diventare molto difficile da organizzare, dato che ogni modulo nella repo ha il proprio set di issues e pull requests.

La codebase può sembrare un po’ più spaventosa e il repo è più grande (come dimensione sul filesystem).

Inoltre, la history dei commit diventa una brodaglia di commit da ogni modulo che fa parte del monorepo, rendendola spesso inutilizzabile!

It’s demo time! 🤓

https://media.giphy.com/media/jZAwc1FZ4TednLkWwu/giphy.gif

Integrazione con Vscode

Vi suggerisco di installare l’estensione di Nx per vscode per accelerare lo sviluppo.

Applicazione ReactJS

Creiamo un workspace monorepo con Nx:

npx create-nx-workspace@latest --preset=react

Compiliamo le informazioni richieste per creare un’applicazione ReactJS vuota ed attendiamo che finisca.

Crea workspace

Al termine troveremo la nostra applicazione ReactJS sotto apps/react-demo, di default verranno creati anche i test E2E in apps/react-demo-e2e.

Si noti che i node_modules non vengono creati nella cartella del progetto (apps/react-demo), ma nella root del monorepo. Questo perché Nx gestisce tutti i node_modules con un unico file package.json a livello di root, quindi tutte le dipendenze devono essere specificate lì. Questo ovviamente comporta lo svantaggio di avere sempre una singola versione di ogni dipendenza (#309).

Applicazione React Native

Aggiungiamo le dipendenze di React Native al nostro spazio di lavoro esistente:

yarn add @nrwl/react-native --dev

Dopodiché possiamo creare un’applicazione React Native nel nostro workspace, io l’ho fatto dalla console Nx in vscode, ma il comando generato è stato:

yarn nx generate @nrwl/react-native:application react-native-demo --e2eTestRunner=none --no-install --unitTestRunner=none

Ora avremo anche il progetto react-native-demo nel nostro spazio di lavoro, che possiamo trovare nella cartella apps/react-native-demo.

Logica di business condivisa

Per condividere la logica di business, possiamo semplicemente creare una libreria JS che includeremo in entrambe le applicazioni:

yarn nx generate @nrwl/js:library shared-business-logic --unitTestRunner=none

Si tratta di una libreria, quindi non sarà creata nella stessa cartella delle applicazioni, ma si troverà in libs/shared-business-logic.

Si noti che ogni modifica alla libreria shared-business-logic farà automaticamente scattare un aggiornamento delle applicazioni in esecuzione che dipendono da essa 🪄

Per utilizzare la libreria generata in entrambi i nostri progetti, possiamo semplicemente importare la funzione sharedBusinessLogic in entrambe le applicazioni.

Utilizzo della logica di business condivisa in ReactJS

importare { sharedBusinessLogic } da '@demo/shared-business-logic';
...
Esportare la funzione App() {
  console.log(sharedBusinessLogic());

  return (
    <StyledApp>
      <NxWelcome title="react-demo" />
    </StyledApp>
  );
}

export default App;

Utilizzo della logica di business condivisa in React Native

importare { sharedBusinessLogic } da '@demo/shared-business-logic';
...
export const App = () => {
  const [whatsNextYCoord, setWhatsNextYCoord] = useState<number>(0);
  const scrollViewRef = useRef<null | ScrollView>(null);

  console.log(sharedBusinessLogic());

...

Fatto! 🎉

Codice sorgente della demo

Sconsiglio vivamente di guardare il codice sorgente, perché è quasi al 100% autogenerato da Nx, ma se si vuole dare un’occhiata alla struttura di ciò che genera, questo è il repository con la demo.

Conclusione 🤗

In conclusione, la condivisione della logica di business tra app mobile e web è una buona soluzione al problema della duplicazione del codice. È facile da implementare e può far risparmiare tempo non dovendo scrivere due volte lo stesso codice. Tuttavia, ci sono alcuni svantaggi, come una maggiore complessità di organizzazione che potrebbe rendere l’applicazione più difficile da mantenere nel tempo o imporre restrizioni ai piani di sviluppo futuri.