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.