Io faccio parte di un piccolo team che sviluppa diverse app interne per la nostra azienda. Siamo in procinto di diventare più Agili, questo include in particolare molti test automatizzati. Ora ci troviamo in una situazione in cui, per una o due app su cui abbiamo lavorato più di recente, generalmente apportiamo piccole modifiche reversibili, eseguiamo numerosi test e distribuiamo abbastanza rapidamente con un intervento non molto umano.
Considererei che siamo ancora molto lontani dal fare CI "reali". Per una o due app sopra menzionate probabilmente ci avvicineremo molto presto. Tuttavia, sto avendo difficoltà a immaginare come sarà il nostro setup, a volte in futuro dove abbiamo iniziato a utilizzare CI per la maggior parte del nostro codice legacy.
Supponiamo di avere diverse app standalone, che possono essere distribuite in modo indipendente su server diversi. Abbiamo anche del codice condiviso che è usato da molti di loro e che vogliamo usare in modo coerente tra loro. Ciò include funzioni di utilità, codice che applica elementi come un'interfaccia coerente su alcune parti di tutte le app e le definizioni ORM per il nostro database (condivisa tra tutte le app).
Vedo due alternative, nessuna delle due sembra molto semplice o elegante:
- Tutto il codice viene unito in un enorme repository. Implementazione significa eseguire tutti i test per tutto il codice, test di integrazione per tutto e test di accettazione per tutte le app, prima di lanciare tutto in una volta sola. Questo sembra rendere l'implementazione un affare molto più grande di quanto non fosse in precedenza, contrariamente alla filosofia di CI, che suggerisce che dovrebbe essere veloce e facile. Significa anche che non abbiamo alcuna separazione tra parti diverse della nostra base di codice, con cose che non funzionano mai insieme nello stesso repository per sempre, solo perché entrambi dipendono da una terza cosa.
- Manteniamo separate ciascuna app e ogni componente del codice condiviso. Implementazione significa testare la versione più recente di un componente estensivamente, prima di "rilasciarlo" su un sistema funzionante costituito da tutti gli altri componenti. Questo sembra un design più pulito. Tuttavia, sembra implicare che dobbiamo gestire le dipendenze e il controllo delle versioni per tutte queste cose. Ogni test di integrazione / accettazione deve avere una certa conoscenza di quali versioni degli altri componenti verrà utilizzata e tollerabile. In altre parole, anche se ogni componente diventa molto più affidabile, dobbiamo preoccuparci molto di più su come i pezzi si incastrano tra loro e sui bug di integrazione. Quando i pezzi che dipendono da tutto il resto cambiano, c'è potenziale per la rottura e ovunque.
La via d'uscita da questo dilemma è probabilmente quella di fare una versione limp dell'IC, dove i singoli componenti vengono testati estensivamente e distribuiti rapidamente, ma ci limitiamo ad avere grandi versioni "flag day" delle utility e dello schema del database. Ma sembra davvero che ci siano molti vantaggi di un corretto CI / CD che ci staremmo perdendo. Non è una soluzione esteticamente piacevole, e non stiamo cercando di soddisfare i nostri capi che abbiamo spuntato una scatola, ma vogliamo migliorare le nostre pratiche di lavoro.
Come dovremmo organizzare il codice per un CI corretto e quali sono le lezioni chiave per imparare a pianificare e progettare l'architettura, sia per il codice legacy che per il futuro codice appena scritto?