La conversazione monorepo spesso inizia nel posto sbagliato. Qualcuno si chiede se sia meglio avere uno o più repository, come se si trattasse di una decisione sull'organizzazione delle cartelle. Non lo è. È una decisione su come i team coordinano il lavoro e il repository ne è solo la parte visibile.
Con TypeScript, questa decisione acquista un sapore specifico e potente: la possibilità di condividere tipi tra frontend, backend e librerie interne all'interno dello stesso spazio. Questo è l’argomento che spinge i team seri a guardare al monorepo, e anche l’argomento che nasconde i costi che scoprirai solo in seguito.
Questo testo è per coloro che decidono l'architettura e l'organizzazione del team e hanno bisogno di valutare entrambe le parti prima di firmare.
La vera attrazione: il tipo di contratto dal vivo
Il vantaggio più concreto di un monorepo con TypeScript è il tipo condiviso tra le estremità del sistema. Il backend definisce il formato di una risposta, il frontend utilizza lo stesso formato ed entrambi puntano alla stessa definizione.
Quando il backend modifica il formato dei dati, il frontend interrompe immediatamente la compilazione. Non c'è nessuna riunione di allineamento, non c'è nessun documento contrattuale obsoleto, non c'è il classico bug in cui l'API è cambiata e nessuno ha avvisato l'interfaccia. Il compilatore diventa il meccanismo di coordinamento tra i team.
Ciò risolve una delle maggiori fonti di attrito nei sistemi distribuiti: la disconnessione tra coloro che producono i dati e coloro che li consumano. In archivi separati, il contratto vive nella fiducia e nella documentazione. Nel monorepo digitato, il contratto risiede nel codice e viene controllato con ogni commit. Chi vuole portare questa garanzia ancora più in là, dalla banca all'interfaccia, dovrebbe dare un'occhiata alla sicurezza di tipo end-to-end con tRPC, Drizzle e Prisma](/post/type-safety-ponta-a-ponta-trpc-drizzle-prisma).
Cos'altro offre monorepo
Oltre ai tipi, ci sono vantaggi di coordinamento che vale la pena menzionare. Un cambiamento che attraversa frontend e backend si inserisce in un unico commit e in un'unica revisione, invece di diventare una danza di richieste pull sincronizzate tra repository.
Anche la standardizzazione è più semplice. Una configurazione lint, una versione di TypeScript, un insieme di regole di formattazione che si applicano a tutto. Invece di ramificare ciascun repository nel proprio dialetto, il team mantiene una cultura tecnica unica, che riduce i costi di spostamento tra i progetti.
E c'è il riutilizzo del codice interno. Una libreria di componenti, un insieme di funzioni di utilità, regole di dominio che servono più di un'applicazione. In monorepo si tratta di un pacchetto interno che tutti consumano nella versione corrente, senza il rituale di pubblicare e aggiornare le dipendenze ad ogni modifica.
I compromessi che nessuno mostra all'inizio
Ora l'altra metà della storia, perché un monorepo ben fatto è potente e un monorepo mal fatto è un'ancora.
Il primo costo è la costruzione. Quando tutto convive, servono strumenti che capiscano cosa è cambiato e ricostruiscano solo ciò che è necessario, altrimenti ogni piccolo cambiamento innesca un processo lento che cresce insieme al repository. Senza la memorizzazione nella cache intelligente e la creazione incrementale, il tempo di pipeline diventa una lamentela quotidiana per il team.
Il secondo costo è la governance. Un repository in cui chiunque può importare qualsiasi cosa da qualsiasi luogo degenera rapidamente in un groviglio di dipendenze incrociate. Il frontend finisce per importare qualcosa che aveva senso solo nel backend, e la separazione che esisteva sulla carta nella pratica scompare. Monorepo richiede confini espliciti e la disciplina per mantenerli.
Il terzo costo è meno tecnico e più umano. Un unico repository significa un unico punto di coordinamento. Autorizzazioni, proprietari del codice, revisione, flusso di rilascio. Tutto questo inizia a convivere nello stesso spazio e i team di grandi dimensioni necessitano di regole di proprietà chiare per evitare di intralciarsi continuamente.
##Quando ne vale davvero la pena
La decisione diventa più semplice se si guarda al profilo del problema invece che seguire le tendenze. Monorepo con TypeScript brilla quando frontend e backend appartengono allo stesso team o a team molto vicini e cambiano insieme frequentemente.
Brilla quando esiste un codice di dominio realmente condiviso tra le applicazioni e il costo per mantenerlo sincronizzato in repository separati è già dannoso. Brilla quando il contratto tra i livelli cambia abbastanza da consentire al controllo automatico del tipo di ripagare l'investimento necessario per mettere insieme il framework.
D’altra parte, se i sistemi sono veramente indipendenti, si evolvono a ritmi diversi e appartengono a team che parlano a malapena tra loro, forzando un monorepo si crea un accoppiamento dove non ce n’era. Si paga la complessità senza raccogliere il coordinamento, perché non c'era coordinamento da raccogliere. In questo caso, repository separati con tipi pubblicati come pacchetto con versione spesso funzionano meglio.
Cosa considerare prima di adottare
Prima di spostare qualsiasi cosa, vale la pena rispondere onestamente ad alcune domande, perché le risposte determinano se il monorepo ti aiuterà o ti ostacolerà.
Il primo riguarda la maturità degli strumenti. Disponi o sei disposto a mantenere l'infrastruttura incrementale di creazione e memorizzazione nella cache richiesta da un monorepo sano? Senza questo, il tempo necessario per la pipeline eroderà il guadagno di coordinamento. Si tratta di una decisione di investimento continua, non di una configurazione una tantum.
Il secondo riguarda la disciplina dei confini. Il team è disposto a definire e far rispettare i confini tra i pacchi, anche quando attraversare il confine sembra in quel momento più veloce? Monorepo senza governance diventa spaghetti code su scala più ampia.
Il terzo riguarda il problema che stai risolvendo. Stai adottando monorepo perché la mancanza di tipi condivisi sta causando veri e propri bug e attriti o perché è diventato standard e sembra organizzato? Il primo motivo giustifica il costo. La seconda quasi mai.
La decisione è di organizzazione, non di cartella
Alla fine, il monorepo con TypeScript è una scelta sull'allineamento del modo in cui i team lavorano, con il tipo condiviso che funge da collante tecnico tra di loro. Quando i team hanno davvero bisogno di lavorare insieme, è una delle strutture più efficaci che esistano. Quando non ne hanno bisogno, la complessità viene mascherata da buona pratica.
La leadership tecnica che decide bene è quella che separa il guadagno reale, che è la coordinazione verificabile dal compilatore, dall'estetica di avere tutto in un unico posto. Il primo giustifica l'investimento. La seconda è una trappola costosa.
Se stai valutando questa decisione, per prima cosa delinea il modo in cui i tuoi team modificano insieme il codice oggi e dove si trovano gli attriti. La struttura del repository deve seguire la realtà del lavoro, mai il contrario. Per avere un quadro completo di come i tipi sono alla base di un intero sistema, vale la pena iniziare con perché TypeScript è diventato lo standard.
Leggi anche
- TypeScript avanzato in pratica: cosa distingue l'uso superficiale dall'uso maturo
- Perché TypeScript è diventato lo standard nel Web moderno
- Convalida dei dati con Zod: perché i tipi TypeScript non sono sufficienti
- Server-First: la decisione architettonica di alleggerire il browser
- Sicurezza di tipo end-to-end: dal banco al frontend senza superare i confini
- Micro-frontend: quando e perché adottarlo in progetti scalabili
