Un modo per pensarci è cosa intendi per data / ora ? I computer non sanno cosa siano questi concetti: devono essere programmati in qualche modo. È abbastanza comune per rappresentare volte nel formato UNIX di "secondi dall'epoca", ed è comune inserire un particolare valore in un programma tramite chiamate al sistema operativo. Tuttavia, non importa quanto sia comune questo utilizzo, è importante tenere presente che non è il tempo "effettivo": è solo una rappresentazione logica.
Come altri hanno sottolineato, se hai fatto una "scadenza" usando questo meccanismo, è banale dare da mangiare in un altro momento e interrompere quella "scadenza". Lo stesso vale per i meccanismi più elaborati come chiedere un server NTP (anche su una connessione "sicura", dato che possiamo sostituire i nostri certificati, le autorità di certificazione o anche le patch delle librerie crittografiche). All'inizio potrebbe sembrare che tali individui siano in errore per aggirare il meccanismo, ma potrebbe essere il caso di automaticamente e per buoni motivi . Ad esempio, è una buona idea avere build riproducibili e strumenti per aiutare questo a ripristinare / intercettare automaticamente tali chiamate di sistema non deterministiche. libfaketime fa esattamente questo, Nix imposta tutto data / ora del file in 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 il comportamento di un programma dipende dal tempo logico, allora il il tempo logico cessa di essere una buona misura del tempo "effettivo". In altre parole, le persone generalmente non si scherzano con l'orologio di sistema, ma lo faranno se gli dai un motivo.
Ci sono altre rappresentazioni logiche del tempo: una di queste è la versione del software (la tua app o qualche dipendenza). Questa è una rappresentazione più desiderabile per una "scadenza" che ad es. Tempo UNIX, dal momento che è più specifico della cosa a cui tieni (cambio di set di funzioni / API) e quindi meno probabilità di calpestare preoccupazioni ortogonali (ad esempio giocherellare con il tempo UNIX per aggirare la tua scadenza potrebbe finire per rompere i file di registro, cron jobs , cache, ecc.).
Come altri hanno detto, se controlli la libreria e vuoi "spingere" questa modifica, puoi spingere una nuova versione che depreca le funzionalità (causando avvertimenti, per aiutare gli utenti a trovare e aggiornare il loro utilizzo), quindi un'altra nuova versione che rimuove completamente le funzionalità. Potresti pubblicarli immediatamente uno dopo l'altro, se vuoi, dato che le (di nuovo) versioni sono semplicemente una rappresentazione logica del tempo, non devono essere correlate al tempo "reale". Il controllo delle versioni semantiche può aiutarti qui.
Il modello alternativo è quello di "tirare" il cambiamento. Questo è come il tuo "piano B": aggiungi un test all'applicazione che consuma, che verifica che la versione di questa dipendenza sia almeno il nuovo valore. Come al solito, red / green / refactor per propagare questa modifica attraverso il codebase. Questo potrebbe essere più appropriato se la funzionalità non è "cattiva" o "sbagliata", ma solo "inadatta per questo caso d'uso".
Una domanda importante con l'approccio "pull" è se la versione di dipendenza conta come una "unità" ( di funzionalità ), e quindi merita il test; o se si tratta solo di un dettaglio di implementazione "privato", che deve essere esercitato solo come parte dell'unità reale ( di funzionalità ) test. Direi: se la distinzione tra le versioni della dipendenza conta davvero come una caratteristica dell'applicazione, quindi esegui il test (ad esempio, verificando che la versione di Python sia > = 3.x). In caso contrario, non aggiungere il test (poiché sarà fragile, non informativo e eccessivamente restrittivo); se controlli la libreria, scorri la rotta "push". Se non controlli la libreria, usa solo la versione fornita: se i tuoi test passano, 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 funzioni di una dipendenza (ad es. chiamare determinate funzioni che non funzionano bene con il resto del codice), specialmente se non si controlla la dipendenza: avere il proprio gli standard di codifica vietano / scoraggiano l'uso di queste funzionalità e aggiungono controlli per loro al proprio linter.
Ciascuno di questi sarà applicabile in diverse circostanze.