I primi passi della nostra trasformazione DevOps
5 minuti di lettura

Nel secondo capitolo di questa serie - DevOps for the Win - esploriamo le fasi iniziali cruciali di un percorso di trasformazione DevOps. I primi passi di qualsiasi percorso di trasformazione sono spesso i più difficili. In DevOps, l'identificazione dei passi iniziali giusti, quelli che sono sia d'impatto che realizzabili, è fondamentale per ottenere progressi significativi.

Molte organizzazioni commettono l'errore di implementare ciecamente le best practice senza considerare i loro vincoli specifici, spesso causando frustrazione e stanchezza da fallimento. È invece necessario un approccio più strategico, che identifichi i colli di bottiglia e li elimini sistematicamente.

Come identificare i primi passi?

Un potente principio per identificare il punto di partenza deriva da una ricerca pubblicata 30 anni fa in The Goal: A Process of Ongoing Improvement di Eliyahu M. Goldratt. L'idea è semplice: identificare il collo di bottiglia primario, il fattore limitante che limita le prestazioni del sistema. Nel nostro caso, questo è diventato chiaro quando abbiamo visto che il lavoro del team di sviluppo si accumulava. Le attività venivano avviate ma non completate e il backlog continuava a crescere.

Per scoprire le cause principali, abbiamo organizzato sessioni di approfondimento con i team di sviluppo, i responsabili tecnici e i product manager. Da queste discussioni sono emerse diverse questioni chiave:

  • I team si occupavano di nuovi compiti prima di completare quelli esistenti.
  • Non esistevano criteri chiari per il completamento dei compiti: ciò che gli sviluppatori consideravano "fatto" spesso differiva dalle aspettative degli stakeholder.
  • Non esistevano misure di qualità oggettive prima di contrassegnare il lavoro completato, il che portava a difetti e rilavorazioni.
  • Le frequenti riassegnazioni interrompono la stabilità del team, causando inefficienze.

Creare squadre stabili

Una delle prime misure correttive è stata la ristrutturazione dei team per garantire coerenza e concentrazione. Invece di trattare gruppi di individui come task force ad hoc, abbiamo formato team stabili e longevi con una proprietà chiaramente definita.

La creazione di alcuni team, come quelli di sviluppo, è stata relativamente semplice. Tuttavia, l'organizzazione dei team di supporto, come quelli di infrastruttura, gestione dei progetti, gestione dei prodotti e analisi aziendale, si è rivelata più difficile. Siamo passati attraverso diverse iterazioni per trovare la giusta combinazione.

Seguendo il principio del team-first thinking delineato in Team Topologies di Matthew Skelton e Manuel Pais, noi:

  • Creazione di team piccoli e autonomi (4-7 membri) per promuovere una profonda competenza del settore e la responsabilità.
  • Ha eliminato le dipendenze tra team assicurando che le persone fossero assegnate completamente a un singolo team.
  • Abbiamo perfezionato le strutture dei team, in particolare per le funzioni di supporto come l'infrastruttura e la gestione dei prodotti, per ottimizzare il flusso.

Sfruttare gli strumenti per la visibilità e la gestione

Una volta strutturati i team, siamo passati ad Azure DevOps per la gestione del backlog e del lavoro. Una piattaforma unificata ha permesso di:

  • Migliore visibilità del lavoro , in modo che i team possano seguire i progressi in modo trasparente.
  • Definizioni standardizzate di "fatto" per allineare le aspettative tra le varie funzioni.
  • Migliorare la gestione del backlog, riducendo lo scope creep e i conflitti di priorità.

Applicazione di metriche di qualità oggettive

Per risolvere il problema delle misure di qualità poco chiare prima di contrassegnare le attività come "pronte per il test", abbiamo integrato uno strumento di analisi statica del codice, che fornisce informazioni oggettive su:

  • Copertura del codice
  • Vulnerabilità della sicurezza
  • Odori di codice

Abbiamo anche migliorato la nostra definizione di "Fatto" per rendere i controlli di qualità un passaggio obbligatorio prima di contrassegnare gli elementi di lavoro completati.

Gestione dei lavori in corso (WIP)

Uno dei cambiamenti più significativi è stato il monitoraggio e la limitazione del lavoro in corso (WIP). Un WIP elevato indicava la presenza di colli di bottiglia, us affrontare in modo proattivo le aree in cui il lavoro era in fase di stallo.

Questo approccio sistematico, radicato nelle Topologie degli obiettivi e dei team, ha posto le basi per un miglioramento continuo, riducendo le dipendenze e migliorando la responsabilità.

Nel nostro percorso di trasformazione DevOps, una delle consapevolezze più significative è stata che, dopo i miglioramenti iniziali, il principale ostacolo al flusso si è spostato sulla progettazione del software, in particolare sulla testabilità del nostro codice. Dopo aver affrontato i colli di bottiglia iniziali migliorando l'organizzazione del team, definendo una "definizione di completato" e implementando l'analisi del codice, abbiamo notato che il lavoro si accumulava durante la fase di test. Il codice sviluppato dai team scrum spesso rimaneva in attesa di essere testato dai QA all'interno degli stessi team scrum.

Affrontare il prossimo collo di bottiglia: Il divario nei test

Una volta risolti i colli di bottiglia iniziali, è emerso un nuovo vincolo: i ritardi nei test. Mentre le attività di sviluppo procedevano in modo efficiente, i test diventavano un ostacolo, impedendo rilasci più rapidi. Dopo aver indagato, abbiamo identificato i problemi principali che rallentavano il processo:

  • Affidamento dei test manuali: La maggior parte dei test veniva eseguita manualmente, con conseguenti cicli di feedback lenti e ritardi nel rilevamento dei difetti.
  • Dipendenza dall'interfaccia utente nei test: Dal momento che i componenti dell'interfaccia utente venivano in genere completati per ultimi, i test non potevano essere avviati fino a tardi nel ciclo di sviluppo.
  • Mancanza di automazione proattiva: I test automatizzati, come quelli dell'interfaccia utente basati su Selenium, sono stati scritti solo dopo i test manuali, limitando la loro efficacia nella fase iniziale della convalida.

Passare ad approcci basati sui test

Per eliminare questo collo di bottiglia, abbiamo dato priorità ai test delle unità e delle API rispetto ai test dell'interfaccia utente. Questo cambiamento ha richiesto una modifica fondamentale della mentalità di sviluppo e della progettazione del software:

Miglioramenti ai test API

Per rendere efficiente il test API:

  1. APIs ben definite: APIs essere semplici, ben documentate e disponibili sin dalle prime fasi di sviluppo, in modo che i tester potessero creare casi di test in modo proattivo.
  2. Evitare il database come punto di integrazione:
    • L'utilizzo dei database come punto di integrazione tra i team creava dipendenze che rallentavano i test.
    • La creazione di casi di test richiedeva l'impostazione di database con dati complessi, il che aumentava i tempi di configurazione e limitava la possibilità di testare più scenari.
    • Passando all'integrazione basata su API (principalmente REST su HTTP e, più recentemente, GraphQL), abbiamo ridotto in modo significativo i ritardi e le complessità causati dalle dipendenze dal database.

Questo cambiamento ha consentito di accelerare i progressi nell'automazione dei casi di test per APIs, dimostrando che concentrarsi su progetti API-first ha migliorato sia la testabilità che l'efficienza.

Rafforzare le pratiche di test delle unità

I test unitari hanno rappresentato una sfida maggiore:

  • Rapidi progressi, poi il teatro della copertura: Inizialmente abbiamo raggiunto alti livelli di copertura del codice, ma le revisioni del codice hanno rivelato che molti test unitari erano superficiali, scritti solo per raggiungere gli obiettivi di copertura. Questi test non riuscivano a verificare le funzionalità significative, a coprire gli scenari di errore o a convalidare i casi limite.
  • Cambiare mentalità: Gli sviluppatori dovevano comprendere il valore dei test unitari, non solo per migliorare la qualità del codice, ma anche per accelerare lo sviluppo individuando tempestivamente i problemi.

Sfide nella scrittura di codice testabile

Il più grande ostacolo all'efficacia dei test unitari era la mancanza di testabilità nella base di codice stessa. I problemi principali erano:

  • Funzioni grandi e monolitiche.
  • Componenti strettamente accoppiati.
  • Scarsa separazione delle preoccupazioni.
  • Astrazione insufficiente.

Questi problemi hanno reso difficile isolare e testare efficacemente le singole unità. Per risolvere questo problema, abbiamo:

  1. Linee guida fornite: Abbiamo condiviso le migliori pratiche su:
    • Selezione delle funzioni per i test unitari.
    • Rifattorizzazione del codice per migliorare la testabilità.
    • Progettare e utilizzare i mock per facilitare i test.
  2. Focalizzazione sui miglioramenti incrementali: Gli sviluppatori sono stati incoraggiati ad apportare piccole modifiche significative per migliorare la testabilità nel tempo.

Progressi, sfide e cammino da percorrere

Per i prodotti legacy, il miglioramento della testabilità è rimasto un processo lento a causa dei vincoli architetturali. Tuttavia, queste azioni non miravano solo a migliorare il codice attuale, ma erano un investimento per il futuro:

  • Gli sviluppatori hanno acquisito abitudini migliori, incorporando la testabilità nelle nuove basi di codice.
  • I team sono diventati più autosufficienti, riducendo la dipendenza dalle QA esterne.
  • L'organizzazione ha evitato di ripetere gli errori del passato, garantendo che i prodotti futuri fossero più facili da mantenere ed evolvere.

Il punto chiave da cui partire? DevOps non consiste nell'implementare strumenti o liste di controllo. Si tratta di migliorare continuamente il flusso di lavoro, un vincolo alla volta.

Nel prossimo capitolo di questa serie, esploreremo la "Progettazione per la testabilità". Approfondiremo il modo in cui il miglioramento della progettazione del software può eliminare i vincoli del testing, consentendo cicli di feedback più rapidi e una maggiore qualità del software: innanzitutto nelle strutture dei team, poi nella gestione dei flussi di lavoro e infine nella testabilità, ponendo le basi per una trasformazione DevOps sostenibile.