Progettare per la testabilità: Abbattere la prossima barriera
4 minuti di lettura

Nella nostra serie DevOps for the Win, abbiamo documentato il nostro percorso di trasformazione DevOps. Nel capitolo 1 abbiamo introdotto il Triangolo DevOps: Strumenti, architettura e persone nello sviluppo del prodottodove abbiamo discusso gli elementi fondamentali che determinano il successo di DevOps. Nel Capitolo 2 abbiamo esplorato I primi passi della nostra trasformazione DevOpscondividendo come abbiamo gettato le basi per cambiamenti significativi.

Ora, nel capitolo 3, affrontiamo la prossima grande sfida che abbiamo incontrato: progettare per la testabilità. Dopo aver migliorato la struttura del nostro team, perfezionato la nostra definizione di "completato" e implementato l'analisi automatizzata del codice, ci siamo resi conto che il principale collo di bottiglia nella nostra pipeline si era spostato sulla progettazione del software, in particolare sulla testabilità. Il lavoro si accumulava nella fase di test, us ottenere cicli di rilascio più rapidi. Questo capitolo approfondisce il modo in cui abbiamo superato questa sfida e migliorato la nostra capacità di fornire software di alta qualità in modo efficiente.

Il collo di bottiglia dei test

La ragione principale di questo ritardo è che i test erano prevalentemente manuali e si concentravano sui test dell'interfaccia utente e sui flussi di lavoro degli utenti. Poiché l'interfaccia utente era di solito uno degli ultimi elementi da completare, l'automazione era scarsa o inesistente e i test manuali diventavano l'unico approccio possibile. I casi di test automatizzati dell'interfaccia utente (ad esempio, i test Selenium) sono stati scritti in genere dopo il completamento dei test manuali, principalmente a scopo di regressione.

L'affidamento ai test manuali ha portato a...

  • Ritardi significativi nei rilasci di software.
  • La necessità di implementazioni multiple per consentire test paralleli da parte di più membri QA .

Ciò ha evidenziato l'importanza di rendere il codice più testabile per ottimizzare il flusso di valore. Tuttavia, raggiungere questo obiettivo si è rivelato più difficile del previsto.

Privilegiare i test API e i test unitari

Per affrontare questa sfida, ci siamo concentrati su due aree principali:

  1. Test unitari - Assicurare che i singoli componenti possano essere testati in modo isolato.
  2. Test API - Riduzione della dipendenza dai test basati sull'interfaccia utente e dalle dipendenze dal database.

Test API: Spostamento a sinistra per un feedback più rapido

Abbiamo ridefinito la nostra strategia di test delle API con questi miglioramenti chiave:

  1. APIs ben definite APIs APIs progettate per essere semplici, ben documentate e disponibili sin dalle prime fasi di sviluppo.
  2. Evitare i database come punto di integrazione: affidarsi ai database per l'integrazione ha creato dipendenze che hanno rallentato i test. Ci siamo invece orientati verso un'integrazione basata su API, utilizzando REST su HTTP e GraphQL. In questo modo abbiamo ridotto al minimo i tempi di configurazione del database e migliorato l'automazione dei test.

Questo cambiamento ha ridotto significativamente i ritardi, consentendo un'automazione più rapida e test nelle prime fasi, dimostrando che concentrarsi su progetti API-first ha migliorato sia la testabilità che l'efficienza.

Test delle unità: Un cambiamento di mentalità

Inizialmente, i nostri sforzi per i test unitari hanno portato a un rapido aumento della copertura dei test, ma abbiamo rapidamente identificato dei problemi:

  • Alcuni test erano superficiali, scritti solo per soddisfare gli obiettivi di copertura del codice.
  • Mancava una convalida significativa delle funzionalità, dei casi limite e degli scenari di fallimento.

Per contrastare questo fenomeno, abbiamo sottolineato:

  • Educare gli sviluppatori alla scrittura di test validi.
  • Rifattorizzazione del codice per migliorare la testabilità.

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 lenti ma costanti

Nonostante questi sforzi, i progressi sono stati lenti, soprattutto per i prodotti legacy. L'architettura esistente limitava il numero di test unitari che potevamo scrivere. Tuttavia, queste azioni non miravano solo a migliorare la base di codice attuale, ma rappresentavano un investimento per il futuro:

  • Il miglioramento delle competenze degli sviluppatori nella progettazione di codice testabile ha garantito che i progetti futuri non avrebbero avuto gli stessi problemi.
  • I miglioramenti incrementali hanno evitato le interruzioni, aumentando costantemente la copertura dell'automazione dei test.
  • Un cambiamento di mentalità ha aiutato i team a vedere la testabilità non come un peso ma come una necessità per un successo DevOps sostenibile.

Per i team e le organizzazioni che intraprendono una trasformazione DevOps, la testabilità è un'area critica su cui concentrarsi. Aiuta a ridurre i colli di bottiglia nella fase di sviluppo. Tuttavia, è importante gestire le aspettative: i risultati immediati potrebbero non essere possibili, soprattutto quando si ha a che fare con grandi basi di codice legacy. Il refactoring di questo codice senza sufficienti test unitari e di regressione è una sfida importante.

Lezioni da Il programmatore pragmatico

Per gli scenari in cui non è possibile iniziare con una nuova base di codice, The Pragmatic Programmer: Your Journey to Mastery, di Andy Hunt e David Thomas, offre una guida praticabile:

  • Obiettivo: modifiche incrementali: Concentrarsi sul refactoring di piccole parti gestibili della base di codice.
  • Disaccoppiare i componenti: Ridurre le dipendenze per rendere le singole unità più facili da testare.
  • Scomporre le funzioni monolitiche: Dividere le grandi funzioni in unità più piccole e mirate.
  • Adottare un design modulare: Rendere il codice più testabile e manutenibile migliorando la modularità.

Il messaggio è chiaro: una volta affrontati i colli di bottiglia iniziali, la testabilità dovrebbe diventare un'area di attenzione fondamentale. In questo modo si alleggeriranno i vincoli della fase di test e si potrà consegnare più rapidamente un software di alta qualità.

Guardare avanti

Il nostro percorso volto a migliorare la testabilità us ha insegnato lezioni us sul ruolo della progettazione software nel consentire trasformazioni DevOps senza intoppi. Concentrandoci sulla testabilità, abbiamo affrontato i colli di bottiglia, migliorato le competenze degli sviluppatori e gettato le basi per il successo futuro. Anche se i risultati immediati possono essere lenti, i vantaggi a lungo termine in termini di qualità, efficienza e crescita del team rendono questo investimento utile.

Continuando il nostro viaggio DevOps, la misurazione del successo diventa la prossima sfida chiave. Nel Capitolo 4 analizzeremo come abbiamo stabilito KPI e Dashboard per monitorare i nostri progressi e identificare ulteriori aree di miglioramento.

Restate sintonizzati mentre approfondiamo come il processo decisionale basato sui dati us ha aiutato us i nostri processi DevOps e ottimizzare le prestazioni!