Impedisci la compilazione del codice obsoleto dopo aver raggiunto una scadenza [chiuso]


68

Nel mio team abbiamo ripulito molte cose vecchie in un grande progetto monolitico (intere classi, metodi, ecc.).

Durante le attività di pulizia mi chiedevo se ci fosse una sorta di annotazione o libreria più elaborata del solito @Deprecated. Ciò @FancyDeprecateddovrebbe impedire il completamento della compilazione del progetto se non è stato pulito il vecchio codice inutilizzato dopo che è trascorsa una determinata data.

Ho cercato su Internet e non ho trovato nulla con le funzionalità descritte di seguito:

  • dovrebbe essere un'annotazione o qualcosa di simile da inserire nel codice che si intende eliminare prima di una determinata data
  • prima di quella data il codice verrà compilato e tutto funzionerà normalmente
  • dopo tale data il codice non verrà compilato e ti darà un messaggio che ti avverte del problema

Penso di essere alla ricerca di un unicorno ... Esiste una tecnologia simile per qualsiasi linguaggio di programma?

Come piano BI, sto pensando alla possibilità di fare la magia con alcuni test unitari del codice che si intende rimuovere che iniziano a fallire alla "scadenza". Cosa ne pensi di questo? Qualche idea migliore?


168
L'ammortamento viene eseguito per una versione , non per una data . Se desideri che le persone smettano di utilizzare le funzionalità obsolete, rilascia una versione senza di esse. Questo attirerà la loro attenzione e possono sempre tornare indietro se non possono ancora farlo. Molte persone sono bloccate nelle vecchie versioni. Rompere il loro programma non è la strada da percorrere.
isanae

4
Il piano B sembra solido. Con l'ulteriore vantaggio di poter inserire commenti nel test unit sul motivo per cui è obsoleto. L'aggiunta del commento al codice sorgente non aiuterebbe la leggibilità in un grande monolite
dwana

53
Sembra un unicorno davvero malvagio. Hai un po 'di software che si compila bene, supera tutti i test e lo hai spedito a un cliente. Quindi un giorno, verifichi di nuovo il software e non si costruirà, anche sulla stessa piattaforma di sviluppo. Ora sei costretto a modificare il codice che in precedenza ha superato i test formali o a fare hack malvagi come ripristinare l'orologio del computer.
Simon B

6
Make it @ Deprecated_RemoveMe_2018_06_01 e quindi il 01/06/2018 elimina l'annotazione stessa. Voilà, tutto il codice che utilizza l'annotazione non verrà più compilato! (perché l'annotazione non è stata trovata)
user253751

65
Anni in futuro, uno sviluppatore appena assunto chiederà: perché il tempo sul server di build è impostato su gennaio 2016? E il ragazzo che è lì per 10 anni gli dirà che è necessario o la costruzione si rompe in posti casuali. Sospiro.
Wilbert

Risposte:


62

Non penso che questa sarebbe una caratteristica utile quando proibisce davvero la compilazione. Quando al 01/06/2018 non verrà compilata gran parte del codice compilato il giorno prima, il tuo team rimuoverà rapidamente quell'annotazione, ripulendo o meno il codice.

Tuttavia, è possibile aggiungere alcune annotazioni personalizzate al codice come

@Deprecated_after_2018_07_31

e costruisci un piccolo strumento per scansionare quelle annotazioni. (Un semplice liner in grep lo farà, se non si desidera utilizzare la riflessione). In lingue diverse da Java, è possibile utilizzare un commento standardizzato adatto per "grepping" o una definizione di preprocessore.

Quindi esegui quello strumento poco prima o dopo la data particolare e se trova ancora quell'annotazione, ricorda al team di ripulire urgentemente quelle parti di codice.


9
@Bergi: ehi, questo è solo un esempio, OP può usare versioni o tag di data, qualunque cosa preferiscano nel loro controllo.
Doc Brown,

4
Non vedo alcun vantaggio nel fare questo semplicemente usando le normali funzionalità di deprecazione e guardando l'output del compilatore nella data specifica. Sembra uno scarso utilizzo del tempo degli sviluppatori per reimplementare qualcosa che praticamente esiste già. Anche se hai già un sacco di avvisi (che varrebbe la pena ripulire), sicuramente il compilatore può sputare tutti gli avvisi in un file di testo e quindi grep o cercarlo.
jpmc26

4
@jpaugh Sto raccomandando di non sprecare ore (nota, tempo = denaro) nella costruzione di nuovi strumenti per svolgere attività che puoi già svolgere in modo efficiente con strumenti esistenti, qualunque essi siano.
jpmc26

3
@ jpmc26: vedo due (piccoli) vantaggi: non ricevere tonnellate di avvisi di deprecazione (che porterebbe al rischio di trascurare quelli più importanti) e una possibilità di introdurre criteri di ammortamento diversi (date, versioni, qualunque) per diverse sezioni di codice. Inoltre, il PO ha chiesto esplicitamente di associare l'ammortamento a una data.
Doc Brown

7
Vorrei fare +1 se utilizzassi l'ordine AAAA-MM-GG per la data del tuo esempio, perché ho sempre visto l'ambiguo ordine ~ - ?? - AAAA causare dolore e incomprensioni.
mtraceur,

284

Ciò costituirebbe una caratteristica nota come bomba a orologeria . Non creare bombe a tempo.

Il codice, non importa quanto bene lo strutturi e lo documenti, si trasformerà in una scatola nera quasi mitica mal compresa se sopravvive oltre una certa età. L'ultima cosa di cui chiunque avrà bisogno in futuro è l'ennesima strana modalità di fallimento che li sorprende totalmente di sorpresa, nel peggior momento possibile e senza un ovvio rimedio. Non ci sono assolutamente scuse per produrre intenzionalmente un tale problema.

Guardalo in questo modo: se sei organizzato e consapevole della tua base di codice abbastanza da preoccuparti dell'obsolescenza e seguirla, allora non hai bisogno di un meccanismo all'interno del codice per ricordartelo. In caso contrario, è probabile che tu non sia aggiornato su altri aspetti della base di codice e che probabilmente non sarai in grado di rispondere tempestivamente e correttamente all'allarme. In altre parole, le bombe a tempo non servono a nessuno. Dì semplicemente di no!


74
+1 Questo ti morderà. Mesi dopo. Un venerdì proprio mentre stai cercando di eseguire una distribuzione di emergenza. Ed è un lungo weekend, quindi tutte le persone che ne sanno qualcosa sono fuori sede. Non farlo
Roger Lipscombe

3
Essere d'accordo. L'obsolescenza è un problema organizzativo, non un problema di codifica. Potrei ancora collegare una Apple] [e scrivere BASIC, niente che mi fermi. Ma, avrei voglia di?

19
La soluzione corretta, seguendo la tua direzione "organizzata e consapevole", è quella di sollevare un bug nel tuo sistema di tracciamento dei bug, dicendo "Rimuovi <tale e tale>", con un periodo di tempo suggerito nei commenti. E poi in 6 mesi quando arriva la revisione dei bug per scoprire quali bug dovrebbero essere corretti nella prossima versione, se quel lasso di tempo è imminente, dici "è ora di farlo". È la gestione di base del progetto.
Corse di leggerezza con Monica

1
In effetti, se il tuo programma di rilascio è sufficientemente prevedibile, adesso basta un traguardo.
Corse di leggerezza con Monica

13
Fai riferimento al commento di isanae per un'alternativa: " Se vuoi che le persone smettano di usare le funzionalità deprecate, rilascia una versione senza di loro. Questo attirerà la loro attenzione e possono sempre tornare indietro se non possono ancora farlo. "
Stevoisiak

70

In C # useresti ObsoleteAttributenel modo seguente:

  • Nella versione 1, spedisci la funzione. Un metodo, classe, qualunque cosa.
  • Nella versione 2, viene fornita una funzionalità migliore destinata a sostituire la funzionalità originale. Metti un attributo Obsoleto sulla funzione, impostalo su "avviso" e gli dai un messaggio che dice "Questa funzione è obsoleta. Usa invece la funzione migliore. Nella versione 3 di questa libreria, che verrà rilasciata su tale e tale una data, l'utilizzo di questa funzione sarà un errore. " Ora gli utenti della funzionalità possono ancora utilizzarla, ma hanno il tempo di aggiornare il proprio codice per utilizzare la nuova funzionalità.
  • Nella versione 3, aggiorni l'attributo in modo che sia un errore anziché un avviso e aggiorni il messaggio per dire "Questa funzione è obsoleta. Usa invece la funzione migliore. Nella versione 4 di questa libreria, che verrà rilasciata su tale e tale una data, questa funzione verrà lanciata ". Gli utenti che non hanno rispettato l'avviso precedente ricevono ancora un messaggio utile che dice loro come risolvere il problema e devono risolverlo, perché ora il loro codice non viene compilato.
  • Nella versione 4, si modifica la funzionalità in modo che generi un'eccezione irreversibile e si modifica il messaggio per dire che la funzionalità verrà rimossa interamente nella versione successiva.
  • Nella versione 5, rimuovi completamente la funzione e se gli utenti si lamentano, beh, ehi, hai dato loro tre cicli di rilascio di un avvertimento corretto e possono sempre continuare a usare la versione 2 se ne sono fortemente convinti.

L'idea in questo caso è quella di apportare una modifica sostanziale il più indolore possibile agli utenti interessati e di garantire che possano continuare a utilizzare la funzionalità per almeno una versione della libreria.


2
Credo che questo sia l'approccio corretto, ma cambierei una cosa ... che cambierebbe "se gli utenti si lamentano" con "quando gli utenti si lamentano"
Liath

10
Rimuovere il corpo contemporaneamente a passare a un errore sembra strano. Uno dei vantaggi della versione di errore di deprecato è che consente al codice creato con le versioni precedenti di continuare a funzionare impedendo al codice appena compilato di utilizzarlo. In questo modo rimani compatibile ABI, interrompendo deliberatamente la compatibilità API. Ovviamente un mondo perfetto avresti il ​​versioning semver style, ecc., In modo tale da non eseguire mai il nuovo codice con un'applicazione precedentemente compilata, ma molti progetti non raggiungono mai quell'ideale.
Kevin Cathcart,

@KevinCathcart: è un buon punto; forse è garantito un altro stadio lì dentro! Aggiornerò il testo.
Eric Lippert,

1
In realtà, se stai facendo SemVer, puoi passare direttamente da deprecato nella versione XY0 (qualsiasi deprecazione deve essere una versione minore) a completamente rimosso in X + 1.0.0. Direi che è bello resistere un po 'più avanti (su X + 2.0.0?), Ma questo processo in cinque passaggi probabilmente sta dorando il giglio. Il passaggio successivo dopo "avviso" dovrebbe essere "errore irreversibile" (perché la funzione obsoleta viene sostituita con il codice che genera l'errore). Dal momento che libfoo.so.2e libfoo.so.3possono coesistere tra loro bene, il downstream può continuare a utilizzare la vecchia libreria fino a quando non viene commutato.
Monty Harder,

@MontyHarder: Sicuro. L'esatta sequenza di eventi può essere determinata dalle esigenze dello sviluppatore e della sua comunità di utenti. Il punto più grande, tuttavia, è che dovrebbe esserci una politica ponderata per affrontare questo tipo di problemi di versioning che è chiaramente comunicato agli stakeholder.
Eric Lippert,

24

Hai frainteso il significato di "deprecato". Obsoleto significa:

essere utilizzabile ma considerato obsoleto e meglio evitabile, in genere perché è stato sostituito.

Dizionari di Oxford

Per definizione, verrà ancora compilata una funzione obsoleta.

Stai cercando di rimuovere la funzione in una data specifica. Va bene. Il modo in cui lo fai è rimuoverlo in quella data .

Fino ad allora, contrassegnalo come obsoleto, obsoleto o come lo chiama il tuo linguaggio di programmazione. Nel messaggio, includere la data in cui verrà rimosso e l'elemento che lo sostituisce. Ciò genererà avvisi, indicando che altri sviluppatori dovrebbero evitare il nuovo utilizzo e dovrebbero sostituire il vecchio utilizzo ove possibile. Quegli sviluppatori lo obbediranno o lo ignoreranno e qualcuno dovrà affrontarne le conseguenze quando verrà rimosso. (A seconda della situazione, potresti essere tu o potrebbero essere gli sviluppatori che lo utilizzano.)


Interessato a ciò che il downvoter non è d'accordo.
jpmc26

2
+1. Se usi JIRA per lo sviluppo agile, crea un'attività e inseriscila in uno sprint futuro; adattarsi a qualsiasi altro strumento di gestione del progetto e metodologia segua. Questo è meglio risolto con metodi non tecnici.
Matteo Leggi l'

1
E assicurati anche che la Classe / Lib rimanga nella documentazione come ammortizzata e / o rimossa nella versione Xx
Phil M

12

Non dimenticare che è necessario conservare la capacità di creare ed eseguire il debug di versioni precedenti del codice per supportare le versioni del software che sono già state rilasciate. Sabotare una build dopo una certa data significa anche che rischi di impedirti di eseguire legittimi interventi di manutenzione e supporto in futuro.

Inoltre, sembra una banale soluzione per riportare l'orologio della mia macchina uno o due anni prima della compilazione.

Ricorda, "deprecato" è un avvertimento che qualcosa andrà via in futuro. Quando vuoi impedire forzatamente alle persone di usare quell'API, rimuovi semplicemente il codice associato . Non ha senso lasciare il codice nella base di codice se qualche meccanismo lo rende inutilizzabile. La rimozione del codice ti dà i controlli in fase di compilazione che stai cercando e non ha una soluzione banale.

Modifica: Vedo che fai riferimento a "vecchio codice non utilizzato" nella tua domanda. Se il codice non è realmente utilizzato , non ha senso deprecarlo. Basta cancellarlo.


La risposta migliore di gran lunga, forse sottolinea che l'eliminazione del codice è il modo migliore per risolvere il problema prima nella risposta. Può essere facile scorrere oltre il muro di risposte testuali
Clint

6

Non ho mai visto una tale funzione prima d'ora - un'annotazione che inizia ad avere effetto dopo una data particolare.

Il @Deprecatedpuò essere sufficiente, tuttavia. Cattura gli avvisi in CI e fai in modo che rifiuti di accettare la build se presente. Ciò sposta la responsabilità dal compilatore alla pipeline di compilazione, ma ha il vantaggio di poter (semi) facilmente modificare la pipeline di compilazione aggiungendo ulteriori passaggi.

Si noti che questa risposta non risolve completamente il problema (ad esempio, le build locali sui computer degli sviluppatori continuerebbero comunque a funzionare, anche se con avvisi) e presuppone che sia stata impostata e eseguita una pipeline CI.


4

Stai cercando calendari o liste di cose da fare .

Un'altra alternativa è quella di utilizzare avvisi personalizzati del compilatore o messaggi del compilatore, se si riesce ad avere pochi o nessun avviso nella propria base di codice. Se hai troppi avvisi, dovrai dedicare ulteriore sforzo (circa 15 minuti?) E raccogliere l'avvertimento del compilatore nel rapporto di compilazione che la tua integrazione continua offre su ogni build.

I promemoria che il codice deve essere corretto sono buoni e necessari. A volte questi promemoria hanno scadenze rigorose nel mondo reale, quindi potrebbe anche essere necessario metterli su un timer.

L'obiettivo è ricordare continuamente alle persone che il problema esiste e deve essere risolto in un determinato periodo di tempo - una funzione che interrompe semplicemente la generazione in un momento specifico non solo non lo fa, ma quella caratteristica è essa stessa un problema che deve essere risolto entro un determinato periodo di tempo.


1
Essere d'accordo. Ma se esiste un problema che deve essere risolto entro un determinato periodo di tempo, allora deve diventare la massima priorità di qualcuno al momento giusto. Ricordo che durante una riunione il mio direttore mi ha dato una "massima priorità", poi ha detto " Questa è la tua priorità numero uno" (qualcosa di diverso). Il mio supervisore disse: "Non può avere due priorità numero uno!" Il direttore fu sorpreso. Immagino abbia pensato che ... io potrei. Pianificare che qualcosa venga riparato "al momento giusto" sta pianificando di rimanere senza tempo.

3

Un modo di pensarci è cosa intendi per data / ora ? I computer non sanno quali siano questi concetti: devono essere programmati in qualche modo. È abbastanza comune rappresentare i tempi nel formato UNIX di "secondi dall'epoca", ed è comune inserire un determinato valore in un programma tramite chiamate del sistema operativo. Tuttavia, non importa quanto sia comune questo utilizzo, è importante tenere presente che non è il momento "reale": è solo una rappresentazione logica.

Come altri hanno sottolineato, se hai fissato una "scadenza" utilizzando questo meccanismo, è banale alimentare un tempo diverso e infrangere quella "scadenza". Lo stesso vale per meccanismi più elaborati come la richiesta a un server NTP (anche tramite una connessione "sicura", poiché possiamo sostituire i nostri certificati, autorità di certificazione o persino patchare le librerie di crittografia). All'inizio potrebbe sembrare che tali individui siano in errore per aver aggirato il tuo meccanismo, ma può accadere che sia fatto automaticamente e per buoni motivi . Ad esempio, è una buona idea avere build riproducibili e strumenti che aiutino questo a ripristinare automaticamente / intercettare tali chiamate di sistema non deterministiche. libfaketime fa esattamente questo,imposta tutti i timestamp del file su 1970-01-01 00:00:01, la funzione di registrazione / riproduzione di Qemu simula tutte le interazioni hardware, ecc.

Questo è simile alla legge di Goodhart : se fai in modo che il comportamento di un programma dipenda dal tempo logico, allora il tempo logico cessa di essere una buona misura del tempo "reale". In altre parole, le persone in genere non scherzano con l'orologio di sistema, ma lo faranno se gli dai un motivo.

Esistono altre rappresentazioni logiche del tempo: una di queste è la versione del software (la tua app o alcune dipendenze). Questa è una rappresentazione più desiderabile per una "scadenza" rispetto ad esempio al tempo UNIX, poiché è più specifica per ciò che ti interessa (modifica dei set di funzionalità / API) e quindi meno probabilità di calpestare problemi ortogonali (ad esempio, giocherellare con il tempo UNIX per aggirare la scadenza potrebbe finire per rompere i file di registro, cron lavori, cache, ecc.).

Come altri hanno già detto, se controlli la libreria e desideri "spingere" questa modifica, puoi inviare una nuova versione che depreca le funzionalità (causando avvisi, per aiutare i consumatori a trovare e aggiornare il loro utilizzo), quindi un'altra nuova versione che rimuove il caratteristiche interamente. Se lo desideri, puoi pubblicarli immediatamente dopo l'altro, poiché (di nuovo) le versioni sono semplicemente una rappresentazione logica del tempo, non è necessario che siano correlate al tempo "reale". Il versioning semantico può aiutare qui.

Il modello alternativo è "tirare" il cambiamento. Questo è come il tuo "piano B": aggiungi un test all'applicazione che consuma, che controlla che la versione di questa dipendenza sia almeno il nuovo valore. Come al solito, rosso / verde / refactor per propagare questo cambiamento attraverso la base di codice. Ciò può essere più appropriato se la funzionalità non è "errata" o "errata", ma solo "inadatta a questo caso d'uso".

Una domanda importante con l'approccio "pull" è se la versione di dipendenza conta o meno come "unità" ( di funzionalità ), e quindi merita di essere testata; o se si tratta solo di un dettaglio di implementazione "privato", che dovrebbe essere esercitato solo come parte dei test di unità ( di funzionalità ) effettivi . Direi: se la distinzione tra le versioni della dipendenza conta davvero come una caratteristica della tua applicazione, allora fai il test (per esempio, controllando che la versione di Python sia> = 3.x). Altrimenti, non farloaggiungere il test (poiché sarà fragile, non informativo e eccessivamente restrittivo); se controlli la libreria, segui il percorso "push". Se non controlli la libreria, utilizza semplicemente la versione fornita: se i tuoi test superano, non vale la pena limitarti; se non passano, quella è la tua "scadenza" proprio lì!

Esiste un altro approccio, se si desidera scoraggiare determinati usi delle funzionalità di una dipendenza (ad es. Chiamare determinate funzioni che non giocano bene con il resto del codice), soprattutto se non si controlla la dipendenza: vietare i propri standard di codifica / scoraggia l'uso di queste funzionalità e aggiungi controlli per esse alla tua linter.

Ognuno di questi sarà applicabile in diverse circostanze.


1

Puoi gestirlo a livello di pacchetto o libreria. Controlli un pacchetto e ne controlli la visibilità. Sei libero di ritrarre la visibilità. L'ho visto internamente in grandi aziende e ha senso solo nelle culture che rispettano la proprietà dei pacchetti anche se i pacchetti sono open source o gratuiti da usare.

Questo è sempre disordinato perché i team client semplicemente non vogliono cambiare nulla, quindi spesso hai bisogno di alcuni round di whitelist solo mentre lavori con i clienti specifici per concordare una scadenza per migrare, possibilmente offrendo loro supporto.


Mi piace la parte di supporto. Tutti i cambiamenti avvengono più agevolmente, più piacevolmente e probabilmente con meno difficoltà se le persone che li promuovono offrono supporto. Questo è in parte un effetto psicologico: un buon supporto è cooperativo; prende tutto sul serio. Al contrario, i cambiamenti imposti dall'alto senza coinvolgere gli interessati li fanno sentire ignorati e non collaborativi. (Anche se la cordialità deve essere accoppiata con un disco implacabile per ottenere i cambiamenti.)
Peter - Ripristina Monica

1

Un requisito è introdurre una nozione di tempo nella build. In C, C ++, o altri linguaggi / sistemi che utilizzano un preprocessore C-come costruire 1 , si potrebbe introdurre un timestamp attraverso definisce per il preprocessore in fase di compilazione: CPPFLAGS=-DTIMESTAMP()=$(date '+%s'). Questo probabilmente accadrebbe in un makefile.

Nel codice si confronterebbe quel token e causerebbe un errore se il tempo è scaduto. Si noti che l'utilizzo di una macro di funzione rileva il caso che qualcuno non ha definito TIMESTAMP.

#if TIMESTAMP() == 0 || TIMESTAMP() > 1520616626
#   error "The time for this feature has run out, sorry"
#endif

In alternativa, si potrebbe semplicemente "definire" il codice in questione quando è giunto il momento. Ciò consentirebbe la compilazione del programma, a condizione che nessuno lo utilizzi. Supponiamo che abbiamo un'intestazione che definisce un api, "api.h", e non consentiamo di chiamare old()dopo un certo tempo:

//...
void new1();
void new2();
#if TIMESTAMP() < 1520616626
   void old();
#endif
//...

Un costrutto simile probabilmente eliminerebbe old()il corpo della funzione da qualche file sorgente.

Ovviamente questo non è a prova di sciocco; si può semplicemente definire un vecchio TIMESTAMPin caso di emergenza di venerdì notte menzionata altrove. Ma questo è, credo, piuttosto vantaggioso.

Questo ovviamente funziona solo quando la libreria viene ricompilata, dopodiché il codice obsoleto semplicemente non esiste più nella libreria. Sarebbe Non impedire che il codice client di collegamento a binari obsoleti però.


1 C # supporta solo la semplice definizione di simboli di preprocessore, nessun valore numerico, il che rende questa strategia non praticabile.


Vale anche la pena notare che la definizione di questo preprocessore forzerà la TIMESTAMPricompilazione di tutto il codice che utilizza su ogni build. Inabiliterà anche strumenti come ccache. Ciò significa che il tempo di compilazione tipico per le build incrementali aumenterà in modo significativo a seconda della parte della base di codice interessata dalle funzionalità deprecate in questo modo.
Mindriot

@mindriot Questo è un aspetto interessante. Suppongo che sia vero con ogni metodo che introduce una nozione di tempo nel codice - l'OP ha detto esplicitamente "dopo che una data particolare è passata". Si potrebbe gestire l'aspetto temporale nel sistema di compilazione e lasciare solo il codice, vero. Ma l'OP ha chiesto esplicitamente "qualcosa inserito nel codice". La mia soluzione ha il vantaggio di essere indipendente da qualsiasi metodo di compilazione particolare. Può essere ingannato, ma devi soddisfarlo in un modo o nell'altro.
Peter - Ripristina Monica l'

Hai assolutamente ragione. La tua soluzione qui è essenzialmente l'unica che fornisce una soluzione pratica alla vera domanda del PO . Tuttavia ho trovato importante sottolineare il rovescio della medaglia. Spetterà all'OP valutare i pro ei contro. Penso che una buona via di mezzo potrebbe anche essere raggiunta, diciamo, dividendo il TIMESTAMPvalore per, diciamo, 86400, per ottenere una granularità quotidiana e quindi meno ricompilazioni.
Mindriot

0

In Visual Studio, puoi impostare uno script pre-build che genera un errore dopo una determinata data. Ciò impedirà la compilazione. Ecco uno script che genera un errore il 12 marzo 2018 o successivamente ( preso da qui ):

@ECHO OFF

SET CutOffDate=2018-03-12

REM These indexes assume %DATE% is in format:
REM   Abr MM/DD/YYYY - ex. Sun 01/25/2015
SET TodayYear=%DATE:~10,4%
SET TodayMonth=%DATE:~4,2%
SET TodayDay=%DATE:~7,2%

REM Construct today's date to be in the same format as the CutOffDate.
REM Since the format is a comparable string, it will evaluate date orders.
IF %TodayYear%-%TodayMonth%-%TodayDay% GTR %CutOffDate% (
    ECHO Today is after the cut-off date.
    REM throw an error to prevent compilation
    EXIT /B 2
) ELSE (
    ECHO Today is on or before the cut-off date.
)

Assicurati di leggere le altre risposte su questa pagina prima di utilizzare questo script.


-1

Capisco l'obiettivo di ciò che stai cercando di fare. Ma come altri hanno già detto, il sistema di compilazione / compilatore non è probabilmente il posto giusto per imporlo. Suggerirei che il livello più naturale per applicare questa politica sia SCM o le variabili di ambiente.

Se lo fai, aggiungi fondamentalmente un flag di funzionalità che contrassegna un'esecuzione pre-ammortamento. Ogni volta che costruisci la classe deprecata o chiami un metodo deprecato, controlla il flag di funzionalità. Basta definire una singola funzione statica assertPreDeprecated()e aggiungerla a ogni percorso del codice deprecato. Se impostato, ignora le chiamate assert. Se non è un'eccezione. Una volta trascorsa la data, disattiva il flag della funzione nell'ambiente di runtime. Eventuali chiamate obsolete persistenti al codice verranno visualizzate nei registri di runtime.

Per una soluzione basata su SCM, suppongo che tu stia usando git e git-flow. (In caso contrario, la logica è facilmente adattabile ad altri VCS). Crea una nuova filiale postDeprecated. In quel ramo elimina tutto il codice obsoleto e inizia a lavorare sulla rimozione di eventuali riferimenti fino a quando non viene compilato. Eventuali modifiche normali continuano ad apportare al masterramo. Continua a fondere eventuali modifiche masteral codice correlate non deprecate postDeprecatedper ridurre al minimo le sfide di integrazione.

Al termine della data di ammortamento, creare un nuovo preDeprecatedramo da master. Quindi postDeprecatedricollegati master. Supponendo che la tua versione vada fuori dal masterramo, ora dovresti utilizzare il ramo post-deprecato dopo la data. Se si verifica un'emergenza o non è possibile fornire risultati in tempo, è sempre possibile eseguire il rollback preDeprecatede apportare le modifiche necessarie su quel ramo.


7
Questo approccio sembra un incubo logistico. Se inizi a mantenere rami paralleli quasi duplicati finirai per passare tutto il tuo tempo a farlo. Rifiuti totali.
Corse di leggerezza con Monica

6
Non posso essere d'accordo sul fatto che il mantenimento di filiali parallele, utilizzandone una semplicemente per rimuovere le funzioni obsolete di molte versioni prima che tu voglia effettivamente rimuoverle dal prodotto, è in alcun modo "lo standard del settore". Qual è lo scopo di quello? Sì, un VCS può eseguire automaticamente alcune fusioni, ma una fusione dovrebbe essere eseguita con l'occhio di uno sviluppatore per risolvere conflitti logici (e cosa succede quando si ottiene un conflitto che non può nemmeno essere risolto in modo lessicale?). Avere un sistema di compilazione arbitrariamente unito ogni giorno per questo è semplicemente ... inutile. Rimuovi la funzione quando è il momento di rimuoverla.
Lightness Races con Monica

3
Perché c'è una buona ragione per mantenere i rami di rilascio (backport delle patch importanti). Non vi è alcuna buona ragione per mantenere un ramo "qualcosa che potrei fare in futuro". È sovraccarico, senza alcun vantaggio. Semplice come quella.
Lightness Races con Monica

4
Dove l'ho preso? È letteralmente la definizione di deprecazione. Hai deprecato qualcosa che potresti rimuovere in futuro. Quindi non c'è disingenuità, nessuna mossa dei pali della porta, e certamente non si inventano cose solo "per vincere l'argomento". Questo non è "un caso d'uso da manuale di ramificazione SCM" in qualsiasi organizzazione per cui voglio lavorare! Immagino che dovremo concordare di non essere d'accordo. Buona serata!
Lightness Races con Monica

2
@lightness - Ci sono molte ragioni per cui deprecare ufficialmente il codice non è solo una "cosa che potremmo fare ogni volta che ci aggiriamo ". Forse il codice deprecato utilizza una libreria, in cui viene eliminato il supporto ufficiale. Forse il codice deprecato è IP la cui licenza scade dopo una data fissa. Forse dopo la data indicata, ci sono nuove normative e il codice non è conforme. La tua soluzione va bene se vivi in ​​una torre d'avorio. Ma le organizzazioni del mondo reale affrontano questo tipo di situazioni in ogni momento. Il software deve soddisfare le esigenze dell'azienda, non viceversa.
user79126
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.