TODO commenta con le scadenze?


51

sfondo

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

Mi sembra che avere il pieno lancio di una modifica richieda più cicli di rilascio introduce un grande potenziale di errore umano. Nell'articolo collegato mostra che sono necessarie modifiche al codice per 2 versioni e una migrazione al database per 3 versioni.

Quello che sto cercando

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

Quello che sto cercando è un modo in cui un commento TODO può avere una scadenza contro di esso, e il nostro sistema di integrazione continua (attualmente indeciso che useremo) rifiuterebbe la build se questa scadenza fosse scaduta.

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

// 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

Sembra abbastanza semplice da implementare, ma mi chiedo se esiste già qualcosa del genere, perché non voglio reinventare la ruota.

Pensieri aggiuntivi

Mi sento come se potessi soffrire di problemi XY qui, dato che le distribuzioni in rotazione e le distribuzioni blu / verde sono considerate una buona pratica, sembra strano che non riesca a trovare una soluzione per rendere gli aggiornamenti del database meno dolorosi. Se pensi che sto esaminando completamente la cosa sbagliata, per favore fammi sapere in un commento! Detto questo, l'esempio di database che ho fornito è solo un esempio e penso che i commenti TODO con scadenze sarebbero utili anche in altre situazioni, quindi anche se mi sto avvicinando a questa situazione specifica, mi piacerebbe davvero rispondere alle mie domanda reale anche. Grazie!

EDIT: ho appena pensato a un'altra situazione in cui questo potrebbe essere utile. Se usi Toggle Feature per attivare parti dell'app quando sono pronte, devi fare attenzione a ripulirle, altrimenti potresti finire con Toggle Debt . I commenti con scadenze potrebbero essere un buon modo per ricordare questo.


19
La questione TODO è più una questione di disciplina che di strumenti.
Brandon,

16
Penso che tutti gli umani commettano errori e gli strumenti possono essere un buon modo per mitigare questo.
Joshua Walsh,


3
Che ne dici di farlo a livello di programmazione. Intendo scrivere in un membro della classe la tua versione. Se l'app non viene avviata se la versione è uguale == 56 con il messaggio "classe y" è necessario disporre di questa funzione, è possibile avere un elenco di tali messaggi. Cosa ne pensi?
Tomer Ben David,

6
Diretto da chi dice male, non sono d'accordo: la nostra base di codice si basa su molti altri componenti su cui non lavoriamo, quindi usiamo TODO <Bug#>:per tracciare soluzioni alternative per problemi con altri componenti. Quando un bug viene eliminato su uno di questi componenti, è possibile trovare e risolvere facilmente le soluzioni alternative pertinenti. Non sostituisce un tracker di problemi, ne semplifica la manutenzione.
TemporalWolf,

Risposte:


53

Questa domanda è davvero due domande in una.

Commenta Todo

Di tutti i modi per tenere traccia degli oggetti d'azione, questo è il peggiore. I commenti di TODO sono utili durante il lavoro attivo o come suggerimento per un manutentore, "ecco qualcosa che potrebbe essere migliorato in futuro". Ma se fai affidamento sui commenti TODO per portare a termine il lavoro, sei destinato a fallire.

Cosa fare al riguardo

I commenti TODO sono fondamentalmente debiti tecnici, quindi dovrebbero essere gestiti come qualsiasi altro debito tecnico. Affrontali subito, se hai tempo, o mettili nel backlog in modo che possano essere monitorati e prioritari.

In generale, e questo è totalmente supponente e aperto al dibattito, i commenti TODO potrebbero essere considerati un odore di codice. Se un commento su TODO arriva al punto di essere controllato nel controllo della versione, devi chiederti, lo farai davvero in questo momento? In caso contrario, va bene. Sii onesto con te stesso e mettilo nel backlog.

Il modo in cui gestite questo arretrato dipende dal processo aziendale, dalla politica aziendale e forse da una certa autonomia personale. Ma hai ancora bisogno di un backlog monitorato e prioritario per assicurarti che accada.

Modifiche al database

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

Processo post-distribuzione

Creare un processo post-distribuzione che viene eseguito come parte della stessa versione. Comunque tu voglia che funzioni. Sull'ultimo sistema su cui ho lavorato, ho progettato una distribuzione in 4 fasi:

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

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

Postapp era riservato ai casi insoliti in cui dovevamo apportare modifiche allo schema incompatibili. In questi casi, preapp avrebbe apportato abbastanza modifiche per rendere compatibile il nuovo codice dell'applicazione (magari creando una vista temporanea per la compatibilità) e postapp avrebbe ripulito tali artefatti temporanei.

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

Distribuire frequentemente

Se si distribuiscono nuove versioni abbastanza frequentemente, è possibile raggiungere un punto in cui portare una modifica tra 2 o 3 versioni è banale. Cicli di rilascio lunghi amplificano il costo delle modifiche al database.


18
I commenti di Todo sono un modo terribile per tenere traccia e dare priorità al lavoro. Sono un modo valido per spiegare perché un po 'di codice finito a metà si sta agitando nel vento. In un mondo perfetto nessun codice lo fa mai. Nel frattempo, in questo ...
candied_orange,

6
... a volte è bello avere un modo per tenere traccia del debito tecnico che nessuna quantità di deprioritizzazione da capo a può nascondere. Sicuramente non avrai credito per averlo risolto. A volte lo aggiusti comunque.
candied_orange

3
Quindi la strategia con la post-app è che quelle migrazioni vengono eseguite una volta che la distribuzione dell'app è andata a buon fine? E il codice? Supponiamo che tu stia rinominando una colonna da last_name a cognome. Il tuo vecchio codice utilizza last_name. Esegui la migrazione del DB per aggiungere il cognome e modificare il codice per utilizzare il cognome, se disponibile, altrimenti last_name. Dopo che la distribuzione è stata completamente implementata, esegui la migrazione successiva trascinando la vecchia colonna last_name. Ma il tuo codice contiene ancora il codice per last_name, che ora è inutilizzato e quindi debito tecnico. Come imposti la pulizia?
Joshua Walsh,

3
Mentre la gestione degli elementi di azione nei commenti è davvero un modo terribile, avere i commenti che creano automaticamente problemi in un sistema di tracciamento può essere un buon strumento per non dimenticare di farlo perché sei attualmente nel mezzo di codificare qualcosa e non vuoi cambiare contesto al sistema di tracciamento dei problemi.
PlasmaHH,

6
IMHO a questa risposta manca il punto. L'OP ha chiesto una soluzione in cui l'IC informi il team quando è stata dimenticata un'importante pulizia, senza ingombrare il "sistema di gestione dei problemi" (i commenti TODO erano solo un esempio, forse non la soluzione ideale per questo). L'OP ha fornito alcuni buoni motivi per cui non vuole usarlo prima. Tuttavia, questa risposta suggerisce di affidarsi completamente al backlog, che nel caso del PO non è altro che il suo "sistema di gestione dei problemi". Quindi IMHO questa risposta ignora il nocciolo della domanda e non presenta una soluzione.
Doc Brown,

24

Non utilizzare TODO. Hai già un elenco TODO nel tuo progetto. Si chiama tracker dei problemi.

Penso che il vero problema sia in questa frase:

possiamo creare un ticket nel nostro sistema di gestione dei problemi, che crea disordine e potrebbe anche essere spostato in uno sprint successivo o nel backlog dalla direzione.

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

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

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

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


Un buon consiglio, penserò a come possiamo far funzionare il sistema di gestione dei problemi per questo scopo. Mi piace anche l'idea di "Forse anche qualcosa di automatico ha senso dove logicamente fai una distribuzione", sto cercando di pensare a come possiamo farlo. Non sono sicuro che sia realisticamente possibile però.
Joshua Walsh,

11
È del tutto ragionevole avere commenti sul modulo // TODO(#12345): Frobnicate the sprocket before passing it along, a condizione che il bug # 12345 sia un numero di problema "reale" e che il problema sia assegnato a qualcuno. Questo rende la lettura più semplice della fonte chiarendo: "No, il passaggio frobnicato non si nasconde in uno dei metodi di supporto, è semplicemente completamente implementato. Vai a guardare il bug # 12345 per più contesto." Idealmente, si avrebbe una linter giornaliera su base di codice alla ricerca di numeri di emissione chiusi o non validi, ovviamente.
Kevin,

9

Quello che sto cercando è un modo in cui un commento TODO può avere una scadenza contro di esso, e il nostro sistema di integrazione continua (attualmente indeciso che useremo) rifiuterebbe la build se questa scadenza fosse scaduta.

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

// TODO by v55: crea la migrazione per spostare i vincoli in una nuova colonna, rimuovi i riferimenti alla vecchia colonna nell'app // TODO by v56: crea la migrazione per eliminare la vecchia colonna

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

Puoi collegare 55 al monitoraggio della versione o semplicemente richiederlo.

Diventa interessante se vuoi controllare // TODO entro la v54 quando fai 55. Piuttosto allora cerca nella base di codice 55 volte cerca solo // TODO per. Quindi filtrare quel risultato da 1 a 55. Ora 56 non attiverà un errore.

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


4
In questo caso non facciamo raccomandazioni qui.
candied_orange

3
Se esiste un nome generico per questo genere di cose che può essere fornito, ma se leggi la pagina che hai collegato la riga relativa ai consigli ti indica questo: softwareengineering.meta.stackexchange.com/a/6487/131624
candied_orange

6
Per essere chiari, è il tuo commento a cui mi oppongo piuttosto che l'intera domanda.
candied_orange

2
I siti di @YM_Industries SE tendono ad essere autonomi, le raccomandazioni sono sostanzialmente semplici risposte con collegamenti a siti esterni o ti invitano a cercarlo su Google invece di un collegamento, ma alla fine è lo stesso. Potrebbero scadere e diventare morti. Quindi una domanda sulla raccomandazione è fuori tema, tuttavia è qualcuno che vuole menzionare uno strumento come complemento di una risposta o un semplice commento, può farlo.
Walfrat,

2
"Mi chiedevo se esiste una soluzione esistente" - prova a chiederci a softwarerecs.stackexchange.com
Mawg

4

Abbiamo avuto un problema molto simile nel nostro team. Per risolvere questo, abbiamo scritto un controllo di analisi statica che gestisce questi TODO controllando il problema JIRA o Git Issue a cui fanno riferimento. La nostra build fallisce quando il problema specificato passa oltre la colonna "In sviluppo".

Pertanto possiamo comodamente avere TODO senza preoccuparci che vengano dimenticati.

Ho creato un'implementazione open source di questo, in Java. Sì, una dichiarazione di non responsabilità è che ho scritto questo, ma come ho detto, è completamente open source e concesso in licenza.

Lo strumento si chiama Westie e un esempio della verifica dei problemi di Jira è su README.md. Vedi anche GitIssueAnalyser.

Per evitare l'autopromozione se hai ulteriori domande, inviami un messaggio. Se decidi di usarlo e hai qualche suggerimento, ti preghiamo di sollevare problemi su github.


1
Questo è figo! Usiamo anche JIRA, potrei cercare di usarlo. Non risolve davvero le mie preoccupazioni sulla creazione di disordine nel nostro sistema di gestione dei problemi, ma almeno garantirà che non possono essere dimenticati.
Joshua Walsh,

@YM_Industries Sono contento. Sarei felice di accettare qualsiasi contributo o lavoro su qualsiasi questione sollevata.
tjheslin1,

4

Non fare. Fallo ora.

TLDR: scrivere (e testare) gli script DB ora, non più tardi; basta codificarli in modo che la loro esecuzione dipenda dalla versione DB.

Esempio

Per un esempio, immaginiamo che desideri cambiare il nome di una colonna da SSNa TaxID, un requisito comune quando si diventa internazionali.

Per far sì che ciò accada, forse avrai temporaneamente sia una TaxIDche una SSNcolonna. E pur supportando entrambe le versioni, avrai un trigger per aggiornare l'una dall'altra. Ma non vuoi mantenere quel grilletto all'infinito, quindi più tardi, quando la compatibilità con le versioni precedenti non è più necessaria, vuoi che il grilletto venga rimosso (e la SSNcolonna rilasciata). Codificheremo tutto ciò in anticipo senza la necessità di articoli ToDo.

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

Ecco i passaggi.

1. Configurare la tabella delle versioni

  1. Aggiungi una singola tabella chiamata Configurationcon due colonne Namee Value.

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

  3. Aggiungi una riga con a Namedi "CompatibleWith" e imposta il Valuenumero di versione minimo con cui la distribuzione deve essere compatibile.

Ispezionare e aggiornare queste righe prima di ogni distribuzione.

2. Modifica gli script di distribuzione

  1. Aggiungi uno script che crea una nuova colonna di TaxIDfianco a fianco SSNe la popola dalla SSNcolonna. Racchiudere questo codice in Ifun'istruzione che controlla TargetVersion; se la versione di destinazione è troppo bassa (ovvero TaxIDnon è ancora necessaria), 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 viene popolato TaxIDdurante l'inserimento o l'aggiornamento SSNe viceversa. Racchiudere questo codice in Ifun'istruzione che controlla la versione di destinazione e la versione compatibile; salta se TargetVersion è troppo basso ( TaxIDnon è necessario) o se la versione CompatibleWith è troppo alta (il SSNcampo 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 SSNcolonna. Racchiudere in Ifun'istruzione che rimuove la colonna solo se la versione di CompatibleWith è sufficientemente alta ( SSNnon è più necessaria).

    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 distribuzione con qualsiasi combinazione di numeri di versione Blu / Verde che desideri supportare nella produzione. Puoi testare non appena il codice è pronto, manipolando la Configurationtabella nel tuo ambiente QA.

4. Nel tuo playbook di distribuzione

Aggiungi un passaggio per un tecnico per aggiornare la versione CompatibleWith e le righe TargetVersion. Se si sta eseguendo la distribuzione su Blue, impostare TargetVersion sul numero di versione di Blue e la versione Compatibile con il numero di versione di Green; invertirli se stai distribuendo Green.

insidie

È corretto che gli script di distribuzione facciano riferimento e facciano affidamento su quei numeri di versione contenuti nella tabella DB. NON codice di runtime.

Se inizi a scrivere il tuo codice di 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 del runtime deve essere testato; se porti avanti queste condizioni in futuro, il QA dovrà mettere insieme una matrice di dolore per convalidarle con ogni singolo rilascio. 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 anticipo (e testarlo anche) senza timore che verrà eseguito troppo presto. Inoltre, il codice pulirà il trigger di compatibilità con le versioni precedenti quando arriva il momento senza che tu debba preoccuparti ulteriormente.

In questo modo puoi scrivere e testare tutto il codice in anticipo, quando ci stai pensando, e non hai bisogno di occuparti di quei commenti disordinati.


Mi piace molto questo approccio, è più elegante dei commenti ToDo. Ci ho pensato poco dopo aver fatto questa domanda e stavo pensando di fare un altro post chiedendomi come implementarlo al meglio, ma ho pensato che avrei fatto prima le mie ricerche. Il trucco per noi è che stiamo usando Phinx per le nostre migrazioni di database, e non lo supporta davvero. Quando avrò tempo cercherò un modo per estenderlo per supportare questo tipo di flusso di lavoro. Questo approccio non risolve il problema di come garantire che il codice di compatibilità all'indietro venga rimosso dal mio livello app, ma è elegante per il problema DB.
Joshua Walsh,

1

Stai ricevendo un sacco di respingimenti sulla tua idea di TODO, ma personalmente non vedo alcun problema. Alla fine, il modo migliore (e più semplice) per assicurarsi che la migrazione entri in produzione è fallire un test unitario se non lo fa. Ci vorrà letteralmente meno di un minuto per spegnere 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.


1
Sì, speravo idealmente di trattare un TODO scaduto come un test fallito. La quantità di respingimenti nei confronti di TODO mi ha sorpreso un po ', so che non sostituiscono un sistema di gestione dei problemi, ma data la prevalenza di TDD / BDD è chiaro che non ci sono problemi reali con la definizione dei requisiti nel codice e l'utilizzo del codice per far rispettare completamento delle funzionalità.
Joshua Walsh,

-2

Nessuno sembra concentrarsi sulla radice della sua lamentela, ovvero il fatto che le modifiche al database possono richiedere troppi cicli di rilascio. Vuole proseguire con il suo programma di distribuzione blu / verde e la soluzione dovrebbe già essere lì, ma a meno che non mi 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. Dal momento che sembra che il database sia il polo lungo nella tenda, dovrebbe essere duplicato anche in modo tale che, indipendentemente dal tempo o dal numero di cicli di rilascio necessari per implementare le modifiche al database sul sistema offline, non diventano attive fino al completamento e completamente testato. Nel frattempo gli script di sistema offline possono mantenere il database offline completamente aggiornato quotidianamente.


1
La replica del database in una distribuzione blu / verde provoca molti mal di testa. Quando il mio prod env si trova tra il blu e il verde, (carico del 50% distribuito a ciascuno, ad esempio), ho bisogno che il codice di replica mantenga sincronizzati entrambi i database, anche se i loro schemi sono diversi. Dalla ricerca che ho fatto sembra che la maggior parte delle persone nel mondo reale abbia un'istanza DB condivisa tra le loro pile blu e verde. Non vedo questo come un grosso problema fino a quando le migrazioni del database sono abbastanza rapide. Le pile blu / verdi devono intrinsecamente condividere alcune risorse, per lo meno il bilanciamento del carico / proxy inverso.
Joshua Walsh,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.