Non è scalabile mantenere un fork del software per client, indipendentemente dal fatto che si tenti di mantenerlo come repository multipli o come filiali multiple in un repository. Non sarai in grado di applicare modifiche trasversali a tutti i tuoi clienti, se non con uno sforzo straordinario. Le modifiche trasversali comuni sono refactoring, ridisegni o correzioni di sicurezza.
La soluzione è duplice:
-
Riconoscere che avere una distribuzione individuale per un client non è la stessa cosa che eseguire un singolo progetto per quel client. È possibile distribuire con diverse configurazioni dalla stessa base di codice.
-
Crea varianti specifiche per il cliente tramite funzionalità di attivazione / disattivazione, configurazione in fase di esecuzione o di runtime, sistemi di plug-in e integrazione delle dipendenze.
Non apportare modifiche hardcode. Se hai più di un cliente, te ne pentirai. Invece, rendere il motore configurabile in modo che possano essere caricati plugin specifici per client. Quando vuoi modificare il comportamento, rifatta il tuo core engine per supportare un plugin lì, per esempio introducendo una nuova interfaccia. Quindi fornire un'implementazione per quell'interfaccia come codice specifico del cliente. Quando vedi che più client potrebbero aver bisogno di quella funzionalità puoi spostare quel codice nel core, ma eventualmente disabilitarlo per i client che non ne hanno bisogno.
Il nucleo condiviso del tuo software è fondamentale per apportare modifiche con uno sforzo minimo. Mentre si evolve, assicurati che rimanga ben progettato. Questo è il tuo framework per la creazione di varianti specifiche del cliente.
Per il layout del repository, dipende se è necessario concedere l'accesso al repository di sviluppo ai client. Altrimenti, considera di mantenere tutto il lavoro in un singolo monorepo. Ad esempio:
crm/
build-tools/
core-engine/ (contains source, tests, default assets)
client-a/ (contains config and client-specific code, tests, assets)
client-b/
...
Se i client hanno bisogno di accedere ai loro repository, allora potrebbe essere meglio creare repository separati per il core engine e gli adattamenti specifici del client. Potrebbe essere meglio trattare il core engine come una libreria utilizzata da app specifiche del cliente. Tuttavia, repository separati rendono più difficile l'applicazione di modifiche all'indietro non compatibili, come la modifica della firma di un metodo o la ridenominazione di una classe.