Una forma de pensar en esto es lo que quieres decir con hora / fecha . Las computadoras no saben cuáles son estos conceptos: tienen que ser programados de alguna manera. Es bastante común representar tiempos en el formato UNIX de "segundos desde la época", y es común alimentar un valor particular en un programa a través de llamadas al sistema operativo. Sin embargo, no importa cuán común sea este uso, es importante tener en cuenta que no es el momento "real": es solo una representación lógica.
Como otros han señalado, si hiciste una "fecha límite" usando este mecanismo, es trivial alimentarlo en un momento diferente y romper esa "fecha límite". Lo mismo ocurre con mecanismos más elaborados, como solicitar un servidor NTP (incluso a través de una conexión "segura", ya que podemos sustituir nuestros propios certificados, autoridades de certificación o incluso parchear las bibliotecas de cifrado). Al principio puede parecer que esas personas tienen la culpa de trabajar alrededor de su mecanismo, pero puede ser el caso de que se haga automáticamente y por buenas razones . Por ejemplo, es una buena idea tener compilaciones reproducibles , y las herramientas para ayudarlo podrían restablecer / interceptar automáticamente tales llamadas de sistema no deterministas. libfaketime hace exactamente eso,establece todas las marcas de tiempo del archivo en 1970-01-01 00:00:01
, la función de grabación / reproducción de Qemu falsifica toda interacción de hardware, etc.
Esto es similar a la ley de Goodhart : si hace que el comportamiento de un programa dependa del tiempo lógico, entonces el tiempo lógico deja de ser una buena medida del tiempo "real". En otras palabras, las personas generalmente no se meterán con el reloj del sistema, pero lo harán si les das una razón.
Hay otras representaciones lógicas del tiempo: una de ellas es la versión del software (ya sea su aplicación o alguna dependencia). Esta es una representación más deseable para una "fecha límite" que, por ejemplo, el tiempo UNIX, ya que es más específica para lo que le interesa (cambiar conjuntos de características / API) y, por lo tanto, es menos probable que pisotee las preocupaciones ortogonales (por ejemplo, jugar con el tiempo UNIX para evitar su fecha límite podría terminar rompiendo archivos de registro, trabajos cron, cachés, etc.).
Como han dicho otros, si controlas la biblioteca y quieres "impulsar" este cambio, puedes impulsar una nueva versión que desaproveche las características (provocando advertencias, para ayudar a los consumidores a encontrar y actualizar su uso), entonces otra nueva versión que elimine el características por completo. Si lo desea, puede publicarlos inmediatamente uno después del otro, ya que (de nuevo) las versiones son simplemente una representación lógica del tiempo, no necesitan estar relacionadas con el tiempo "real". Las versiones semánticas pueden ayudar aquí.
El modelo alternativo es "tirar" del cambio. Esto es como su "plan B": agregue una prueba a la aplicación consumidora, que verifica que la versión de esta dependencia sea al menos el nuevo valor. Como de costumbre, rojo / verde / refactor para propagar este cambio a través de la base de código. Esto puede ser más apropiado si la funcionalidad no es "mala" o "incorrecta", sino simplemente "una mala opción para este caso de uso".
Una pregunta importante con el enfoque "pull" es si la versión de dependencia cuenta o no como una "unidad" ( de funcionalidad ) y, por lo tanto, merece ser probada; o si se trata solo de un detalle de implementación "privada", que solo debe ejercerse como parte de las pruebas de unidad ( de funcionalidad ) reales . Yo diría: si la distinción entre las versiones de la dependencia realmente cuenta como una característica de su aplicación, entonces haga la prueba (por ejemplo, verifique que la versión de Python sea> = 3.x). Si no, entonces noagregue la prueba (ya que será frágil, poco informativa y demasiado restrictiva); si controlas la biblioteca, ve por la ruta "push". Si no controla la biblioteca, simplemente use la versión que se le proporcione: si sus pruebas pasan, entonces no vale la pena restringirse; si no pasan, ¡esa es tu "fecha límite" allí mismo!
Existe otro enfoque, si desea desalentar ciertos usos de las características de una dependencia (por ejemplo, llamar a ciertas funciones que no funcionan bien con el resto de su código), especialmente si no controla la dependencia: prohíba sus estándares de codificación / desaliente el uso de estas funciones y agregue comprobaciones para ellas a su linter.
Cada uno de estos será aplicable en diferentes circunstancias.