TODO commenta con le scadenze?

51

Sfondo

Sto lavorando in un team che sta cercando di implementare distribuzioni zero-downtime. Stiamo pianificando di utilizzare una strategia di distribuzione blu / verde per raggiungere questo obiettivo. Una delle cose che mi sto rendendo conto nel fare la ricerca è quanto sia complicato fare cambiamenti al database. Una semplice operazione come la ridenominazione di una colonna può richiedere 3 cicli di rilascio completi fino al completamento!

Mi sembra che avere l'implementazione completa di una modifica richieda più cicli di rilascio per introdurre un grande potenziale di errore umano. Nell'articolo collegato mostra che le modifiche al codice sono necessarie per 2 rilasci e una migrazione del database è necessaria per 3 versioni.

Cosa sto cercando

Attualmente, se vogliamo ricordare di fare qualcosa, possiamo creare un ticket nel nostro sistema di gestione dei problemi, che crea confusione e potrebbe anche essere spostato in uno sprint successivo o in un backlog da parte della direzione; oppure possiamo creare un commento TODO, che sarà probabilmente dimenticato completamente.

Quello che sto cercando è un modo in cui un commento TODO può avere una scadenza contro di esso, e il nostro sistema di Continuous Integration (corrente indecisa che useremo) rigetterebbe la build se questa scadenza fosse scaduta.

Ad esempio, se rinominiamo una colonna, potremmo creare la migrazione iniziale per essa e quindi due commenti TODO per garantire che vengano create le due migrazioni rimanenti:

// TODO by v55: Create migration to move constraints to new column, remove references to old column in app
// TODO by v56: Create migration to drop old column

Questo sembra abbastanza semplice da implementare, ma mi chiedo se qualcosa del genere esiste già, perché non voglio re-inventare la ruota.

Altre riflessioni

Mi sembra che potrei soffrire di problemi XY qui, dato che le implementazioni a rotazione e le distribuzioni blu / verdi sono considerate una best practice, mi sembra strano che non riesca a trovare una soluzione per rendere meno doloroso gli aggiornamenti del database. Se pensi che sto guardando completamente alla cosa sbagliata, per favore fammelo sapere in un commento! Detto questo, l'esempio di database che ho dato è solo un esempio, e penso che i commenti di TODO con le date dovute siano utili anche in altre situazioni, quindi anche se mi sto avvicinando a questa specifica situazione tutto sbagliato mi piacerebbe davvero rispondere alle mie domanda reale anche. Grazie!

EDIT: ho appena pensato ad un'altra situazione in cui ciò potrebbe essere utile. Se utilizzi i cavicchi funzione per attivare parti della tua app quando sono pronte, devi fare attenzione a pulirle, altrimenti potresti finire con Attiva / disattiva . I commenti con le scadenze potrebbero essere un buon modo per ricordarlo.

    
posta Joshua Walsh 30.05.2017 - 02:12
fonte

7 risposte

52

Questa domanda è in realtà due domande in una.

Commenti di Todo

Di tutti i modi per tracciare gli elementi di azione, questo è il peggiore. I commenti di TODO sono buoni durante il lavoro attivo o come un modo di suggerire un manutentore, "ecco qualcosa che potrebbe essere migliorato in futuro". Ma se ti affidi ai commenti di TODO per il lavoro svolto, sei destinato a fallire.

Che cosa fare a proposito

I commenti di TODO sono fondamentalmente un debito tecnico, quindi dovrebbero essere gestiti come qualsiasi altro debito tecnico. O affrontali subito, se ne hai il tempo, o inseriscili nel backlog in modo che possano essere tracciati e con priorità.

In generale, e questo è totalmente opinato e aperto al dibattito, i commenti di TODO potrebbero essere considerati un odore di codice. Se un commento TODO lo fa fino al momento in cui viene controllato nel controllo della versione, devi chiedertelo, lo seguirai davvero in questo momento? Se no, va bene. Sii onesto con te stesso e mettilo nel backlog.

Il modo in cui gestisci questo arretrato si riduce al processo aziendale, alla politica aziendale e forse a una qualche autonomia personale. Ma hai ancora bisogno di un backlog tracciato e con priorità per assicurarti che accada.

Modifiche al database

Sì, le modifiche al database sono complicate con una politica di zero-downtime. Alcuni trucchi per rendere meno doloroso:

Processo post-distribuzione

Crea un processo post-distribuzione che viene eseguito come parte della stessa release. Comunque vuoi che funzioni. Nell'ultimo sistema su cui ho lavorato, ho progettato una distribuzione in 4 fasi:

  1. script di database preapp
  2. applicazioni web
  3. script di database postapp
  4. script del database delle finestre di manutenzione

L'idea era che, laddove possibile, avremmo messo il maggior numero possibile di modifiche al database in preapp.

Postapp era riservato ai casi inusuali in cui dovevamo apportare modifiche allo schema incompatibili. In questi casi, preapp farebbe abbastanza modifiche per rendere il nuovo codice applicativo compatibile (magari creando una vista temporanea per la compatibilità), e postapp eliminerebbe tutti questi artefatti temporanei.

La fase della finestra di manutenzione era riservata alle modifiche che richiedevano realmente tempi di inattività o in cui il rischio o il costo di una distribuzione dal vivo non ne valeva la pena. Ad esempio, gli script che modificano enormi quantità di dati potrebbero dover bloccare un'intera tabella.

Distribuisci frequentemente

Se distribuisci le nuove versioni abbastanza frequentemente, puoi raggiungere un punto in cui portare una modifica su 2 o 3 rilasci è banale. I cicli di rilascio lunghi amplificano il costo delle modifiche al database.

    
risposta data 30.05.2017 - 03:32
fonte
24

Non usare TODOs. Hai già una lista TODO nel tuo progetto. Si chiama issue tracker.

Penso che il vero problema sia in questa frase:

we can create a ticket in our issue management system, which creates clutter and also might get moved to a later sprint or the backlog by management.

Se il tuo tracker di problemi crea troppa confusione, trova i modi per risolverlo. Forse un tipo di problema speciale / tag che comporta meno cerimonia. Forse sotto-problemi. Forse meno cerimonia del tutto. Non possiamo davvero dirlo. Ma se il tuo tracker di problemi crea così tanto lavoro, che le persone formulano piuttosto una domanda elaborata su un forum pubblico piuttosto che aggiungere quel problema, qualcosa è seriamente sbagliato.

Se la tua gestione ritarda indebitamente l'ultima parte di un'attività hai due opzioni:

  1. parla al tuo management perché questa è una cattiva idea.

  2. gestirlo come una singola attività. Questa potrebbe essere la soluzione gold standard. In un mondo perfetto dovresti essere in grado di apportare le tre modifiche necessarie in ogni passaggio. Applicare uno al ramo principale, lasciarlo costruire e distribuire. Nel frattempo, applica il secondo al ramo principale, lascia che si sviluppi e distribuisca e così via in modo che tutto avvenga nello stesso sprint e, in caso contrario, non viene eseguito. Forse anche qualcosa di automatico ha senso dove fai logicamente una distribuzione, ma in realtà è divisa in 3.

risposta data 30.05.2017 - 07:47
fonte
9

What I'm looking for is a way that a TODO comment can have a deadline against it, and our Continuous Integration system (current undecided which we'll use) would reject the build if this deadline was expired.

Ciò che chiedi è fattibile se sei disposto a fare il lavoro e a seguire.

// TODO by v55: Create migration to move constraints to new column, remove references to old column in app // TODO by v56: Create migration to drop old column

grep per //TODO by v55 quando è il momento di distribuire v55. Distribuire build esegue uno script che lo fa come test di integrazione.

Puoi collegare 55 al tuo monitoraggio della versione o semplicemente richiederlo.

Diventa interessante se vuoi controllare // TODO per v54 quando fai 55. Piuttosto, cerca nel codice base 55 volte solo per cercare // TODO per. Quindi filtra il risultato da 1 a 55. Ora 56 non provocherà un errore.

Potresti pensare "oh non ne avremo bisogno, li aggiusteremo ogni volta finché avremo il controllo". No. No, non lo farai.

    
risposta data 30.05.2017 - 02:43
fonte
4

Abbiamo avuto un problema molto simile nel nostro team. Per risolvere questo problema abbiamo scritto un controllo di analisi statico che gestisce questi TODO controllando il problema JIRA o il problema di Git a cui fanno riferimento. La nostra build ha esito negativo quando il problema specificato si sposta oltre la colonna "In sviluppo".

Quindi possiamo comodamente avere TODO senza preoccuparci che vengano dimenticati.

Ho creato un'implementazione open-source di questo, in Java. Sì, un disclaimer è che ho scritto questo, ma come ho detto è completamente open source e con licenza.

Lo strumento si chiama Westie e un esempio del correttore del problema di Jira si trova su README.md. Vedi anche GitIssueAnalyser.

Per evitare l'auto promozione se hai ulteriori domande, mandami un messaggio. Se decidi di usarlo e avere suggerimenti, ti preghiamo di segnalare eventuali problemi su github.

    
risposta data 30.05.2017 - 19:43
fonte
4

Non fare. Fallo ora.

TLDR: scrivi (e verifica) i tuoi script DB ora, non più tardi; basta codificarli in modo che la loro esecuzione sia subordinata alla versione di DB.

Esempio

Per un esempio, immaginiamo di voler cambiare il nome di una colonna da SSN a TaxID , un requisito comune quando si va all'estero.

Per fare in modo che ciò accada, forse avrai sia una colonna TaxID che una colonna SSN . E pur supportando entrambe le versioni, avrai un trigger per aggiornarne l'una dall'altra. Ma non vuoi mantenere questo trigger a tempo indeterminato, quindi più tardi, quando la compatibilità all'indietro non è più necessaria, vuoi rimuovere quel trigger (e la colonna SSN è caduta). Stiamo andando a codificare tutto ciò in anticipo senza bisogno di elementi ToDo.

Nel nostro esempio, implementeremo la build 102 (che ha la nuova colonna) mantenendo la compatibilità con la build 101 (che non lo fa).

Ecco i passaggi.

1. Imposta la tabella delle versioni

  1. Aggiungi una singola tabella chiamata Configuration con due colonne, Name e Value .

  2. Aggiungi una riga con Name di "TargetVersion" e imposta Value sulla versione della nuova build da distribuire.

  3. Aggiungi una riga con Name di "CompatibleWith" e imposta Value sul numero di versione minimo con cui la distribuzione deve essere compatibile.

Ispeziona e aggiorna queste righe prima di ogni distribuzione.

2. Modifica gli script di distribuzione

  1. Aggiungi uno script che crea una nuova colonna di TaxID , affiancata a SSN e la popola dalla colonna SSN . Racchiudere questo codice in un'istruzione If che controlla TargetVersion; se la versione di destinazione è troppo bassa (ovvero il TaxID non è ancora necessario), salta.

    SELECT @TargetVersion = TargetVersion FROM Configuration
    IF @TargetVersion < '102' THEN RETURN
    ALTER TABLE Customer ADD COLUMN taxID VarChar(12) NOT NULL
    UPDATE Customer SET TaxID = SSN
    
  2. Aggiungi uno script che crea un trigger che popola TaxID quando si inserisce o si aggiorna SSN e viceversa. Racchiudere questo codice in un'istruzione If che controlla la versione di destinazione e la versione compatibile; salta se TargetVersion è troppo basso (il TaxID non è necessario) o se la versione di CompatibleWith è troppo alta (il campo SSN non è necessario).

    SELECT @TargetVersion  = TargetVersion,
           @CompatibleWith = CompatibleWith 
    FROM Configuration
    IF @TargetVersion  < '102' THEN RETURN
    IF @CompatibleWith > '101' THEN RETURN
    CREATE TRIGGER SSNAndTaxIDTrigger ON Customer etc.
    
  3. Aggiungi uno script per rimuovere la colonna SSN . Racchiudere in un'istruzione If che rimuove la colonna solo se la versione CompatibleWith è sufficientemente alta ( SSN non è più necessario).

    SELECT @CompatibleWith = CompatibleWith FROM Configuration
    IF @CompatibleWith <= '101' THEN RETURN
    IF OBJECT_ID('SSNAndTaxIDTrigger') IS NOT NULL DROP TRIGGER SSNAndTaxIDTrigger
    IF EXISTS (SELECT * FROM syscolumns c JOIN sysobject o ON o.id = c.is WHERE o.Name = 'Custeomr' AND c.Name = 'SSN') BEGIN
        ALTER TABLE Customer DROP COLUMN SSN
    END
    

3. Test

Assicurati di testare la tua implementazione con qualsiasi combinazione di numeri di versione Blue / Green che desideri essere in grado di supportare in produzione. Puoi testare non appena il codice è pronto, modificando la tabella Configuration nel tuo ambiente QA.

4. Nel tuo playbook di implementazione

Aggiungi un passaggio per un tecnico per aggiornare la versione CompatibleWith e le righe TargetVersion. Se stai distribuendo su Blu, imposta TargetVersion sul numero di versione di Blue e la versione di CompatibleWith sul numero di versione di Green; invertirli se stai distribuendo Green.

insidie

È OK per i tuoi script di implementazione fare riferimento e fare affidamento su quei numeri di versione contenuti in quella tabella DB. NON codice di runtime.

Se inizi a scrivere il tuo codice runtime per ispezionare i numeri di versione, stai introducendo un nuovo livello di complessità nella tua applicazione che potrebbe potenzialmente diventare un enorme problema di manutenibilità. Ogni percorso di esecuzione runtime deve essere testato; se porti avanti queste condizioni andando avanti, il QA dovrà mettere insieme una matrice del dolore per convalidarle con ogni pubblicazione. Il mio consiglio è di mantenere condizioni come queste solo negli script di distribuzione.

Il risultato di tutto questo

Alla fine, dovresti essere in grado di scrivere tutto il codice in primo piano (e testarlo anche tu) senza temere che si stia eseguendo troppo presto. Inoltre, il codice eliminerà il trigger di compatibilità all'indietro quando sarà il momento, senza che tu debba preoccuparti ulteriormente.

In questo modo puoi scrivere e testare tutto il codice in primo piano, quando ci stai pensando, e non devi occuparti di quei disordinati commenti ToDo.

    
risposta data 30.05.2017 - 20:59
fonte
1

Stai ricevendo un sacco di respingimento sulla tua idea TODO, ma personalmente non vedo alcun problema. Alla fine, il modo migliore (e più semplice) per assicurarsi che la migrazione entri in produzione è il fallimento di un test di unità, se così non fosse. Ci vorrà letteralmente meno di un minuto per eliminare una funzione di migrazione vuota che genera un'eccezione se la versione è 55 o più (o qualunque siano i requisiti).

Quindi, se provi a rilasciarlo, finirai con un test fallito e qualcuno dovrà trasformare quell'eccezione in un vero codice di migrazione.

    
risposta data 02.06.2017 - 20:43
fonte
-2

Nessuno sembra concentrarsi sulla radice del suo reclamo, che è il fatto che le modifiche al database possono richiedere troppi cicli di rilascio. Vuole continuare con il suo programma di distribuzione blu / verde e la soluzione dovrebbe già essere lì, ma a meno che manchi qualcosa la sua descrizione sembra indicare che esiste un solo database condiviso da entrambi i sistemi. Non è un vero sistema blu / verde se questo è il caso. Poiché sembra che il database sia il polo lungo nella tenda, dovrebbe essere duplicato in modo che, indipendentemente dal tempo o dal numero di cicli di rilascio necessari per implementare le modifiche al database sul sistema offline, non vengano attivati fino al completamento e completamente testato. Nel sistema provvisorio offline gli script possono mantenere il database offline completamente aggiornato quotidianamente.

    
risposta data 30.05.2017 - 20:30
fonte