Accelerare la collaborazione e lo sviluppo Agile con la componentizzazione

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

Il prodotto ha esito positivo, l'organizzazione sta crescendo ed è il momento di aumentare le prestazioni della codebase in modo che corrisponda a questo successo. Con l'aumento del numero di istanze degli ultimi 2-3 team che lavorano in una singola codebase su un singolo prodotto, è possibile che ci si trovi a porre domande come:

  • In che modo i team possono condividere in modo efficiente i componenti riutilizzabili?

  • Ricerca per categorie consentire ai team di funzionalità di eseguire rapidamente l'iterazione senza eseguire istruzioni sul lavoro di altri team?

  • Ricerca per categorie dare ai miei team l'autonomia per eseguire l'iterazione al ritmo giusto per loro?

I team in qualsiasi fase possono trarre vantaggio dalla considerazione di queste domande. Se si è un team stabilito con una codebase legacy, è possibile che si chieda queste stesse domande a cui viene chiesto di offrire più valore, più velocemente che mai. Indipendentemente dalla situazione, la componenteizzazione consente di creare una codebase che si adatta alle dimensioni del team e alla velocità di sviluppo odierna.

Questo articolo illustra in che modo la composizione binaria tramite Azure Artifacts consente di gestire e condividere le dipendenze esterne, il software open source e i componenti condivisi isolati.

Componenti e composizione

La componenteizzazione è il processo di divisione e organizzazione del prodotto in componenti distinti. La maggior parte dei progetti .NET ha già una certa nozione di componenti sotto forma di progetti all'interno della soluzione. Ad esempio, un sito Web di base può essere costituito da un componente front-end, un componente di accesso ai dati e un componente di archiviazione di modelli/dati.

Composizione di origine

Man mano che il prodotto cresce, la soluzione e il modello di progetto possono diventare inefficienti. Le modifiche richiedono più tempo per l'integrazione e sono più difficili da unire, la compilazione diventa più lenta e i componenti iniziano a crescere da un singolo progetto a più progetti. In genere, questo è il punto in cui i team iniziano a suddividere questi set di progetti correlati in soluzioni separate.

Dopo aver esaurito una singola soluzione, il modo in cui si componentizza diventa una domanda interessante. È stata avviata la composizione di origine, in cui a ogni componente viene fatto riferimento tramite un riferimento al progetto in Visual Studio. La composizione di origine è possibile purché l'origine si trovi in un unico limite di composizione: una singola soluzione all'interno di un singolo repository di origine.

Sfortunatamente, questi riferimenti al progetto iniziano a suddividersi quando sono coinvolte più soluzioni. A questo punto, quando la soluzione A dipende dalla soluzione B, deve fare riferimento ai file binari compilati (ad esempio le DLL) prodotti dalla soluzione B. Si tratta di una composizione binaria.

Di conseguenza, questi file binari devono ora essere compilati e resi disponibili per la soluzione A prima di poter compilare correttamente. Esistono alcuni modi per eseguire questa operazione:

  • È possibile archiviarli nel controllo del codice sorgente. A seconda del sistema di controllo del codice sorgente, i file binari possono impostare rapidamente le dimensioni del repository, rallentando i tempi di estrazione e le prestazioni generali del repository. Se si inizia a lavorare in rami, più team possono introdurre lo stesso file binario in versioni diverse, causando conflitti di merge complessi.

  • In alternativa, è possibile ospitarli in una condivisione file, anche se questo approccio presenta alcune limitazioni. Le condivisioni file non dispongono di un indice per ricerche rapide e non forniscono protezione dalla sovrascrittura di una versione in futuro.

Composizione pacchetto

I pacchetti rispondono a molte delle problematiche di riferimento ai file binari. Invece di controllarli nell'origine, è possibile avere una soluzione B produrre i relativi file binari come pacchetti NuGet che un'altra soluzione A può quindi utilizzare. Se la soluzione A e la soluzione B vengono mantenute come componenti separati, in cui le modifiche simultanee in A e B sono rare, la composizione dei pacchetti è un ottimo modo per gestire la dipendenza di A su B. La composizione del pacchetto consente a B di scorrere la propria cadenza, mentre A è libero di ottenere aggiornamenti da B quando la pianificazione di A consente, e consente a più team di scorrere e aggiornare la soluzione B senza influire sulla soluzione A (o altre soluzioni C o D).

Tuttavia, la composizione dei pacchetti presenta un proprio set di sfide. Finora abbiamo esaminato un semplice esempio. Il ridimensionamento della composizione dei pacchetti fino alle dimensioni di una codebase di grandi dimensioni (ad esempio Windows o Bing) può causare una serie di problemi:

  • Comprendere l'impatto delle modifiche di rilievo in un componente basso nel grafico delle dipendenze diventa molto complesso.

  • Le dipendenze a rombo possono diventare un ostacolo significativo all'agilità. In una dipendenza a rombo, i componenti B e C dipendono entrambi da un componente condiviso A, mentre il componente D dipende sia da B che da C. Quando il componente A introduce una nuova versione con modifiche di rilievo, se B viene aggiornato alla nuova versione ma C non, D non può accettare gli aggiornamenti di B senza introdurre un conflitto di dipendenza. In questo semplice esempio, una conversazione con C potrebbe essere tutto ciò che è necessario per risolvere il conflitto. Tuttavia, in un grafico complesso, i diamanti possono diventare rapidamente insolvibili.

  • Quando è necessario applicare modifiche a due componenti composti usando pacchetti, il ciclo di iterazione dello sviluppatore diventa notevolmente più lento. Se il componente A viene aggiornato, richiede la ricompilazione, la ricompressione e la ripubblicazione. Successivamente, il componente B deve essere aggiornato alla versione pubblicata di recente per convalidare la modifica apportata nel componente A. L'uso della composizione di origine, che consente la compilazione simultanea del componente A e B, fornirà in modo coerente un ciclo di iterazione più rapido per gli sviluppatori.

Cosa è consigliabile usare

In generale, abbiamo visto che i team di grandi dimensioni hanno più successo quando usano una combinazione di strategie di composizione. Per determinare qual è il modo giusto per la codebase, iniziare eseguendo il mapping del grafico delle dipendenze del prodotto e iniziare a raggruppare i componenti in set di componenti correlati.

Ad esempio, potrebbe essere disponibile una raccolta di componenti che costituiscono il framework e un altro set di componenti che formano il servizio rivolto all'utente. Quindi, per ogni gruppo di componenti correlati, porre queste domande:

  • È possibile prevedere frequenti check-in tra i set stabiliti per i team?

  • Un singolo team è responsabile dell'intero set?

  • Per un singolo set, esiste una frequenza di rilascio condivisa?

Nell'esperienza è stato rilevato che l'uso della composizione di origine è più efficace per i progetti correlati gestiti da un singolo team o da un gruppo di team correlati. Al contrario, la composizione binaria risulta vantaggiosa per il software open source, le dipendenze esterne (componenti di team distanti o isolati) e componenti condivisi indipendenti.