Es muy común que un programa tenga parámetros de consola de tipo booleano en el que el valor por defecto es
y si se especifica el argumento entonces pasa a considerarse
. Por ejemplo, el programa de Unix
tiene el parámetro
para borrar recursivamente los archivos de las carpetas que encuentra. Por defecto se considera que el comportamiento no es recursivo y si se especifica el parámetro pasa a considerarse que sí. Esto es bastante cómodo y por lo general es una buena idea, por eso se hace tanto, pero esta semana he descubierto un caso en el que haber diseñado un parámetro así ha resultado en un gran problema y me ha hecho pensar en que no siempre es la mejor forma de espeficar bools en la interfaz de parámetros de consola de un programa.
Contexto: trabajas en un programa grande que ya está siendo usado por otras personas. Estás haciendo una funcionalidad nueva del programa y por eso, para no interferir en el uso habitual y no romper las costumbres y automatizaciones de otras personas, quieres hacer que el programa por defecto siga haciendo lo mismo que antes y se le pueda especificar manualmente que haga la cosa nueva. Así que haces el diseño habitual que hemos explicado más arriba. Tienes un
que por defecto es
y un argumento de consola, llamémoslo
, que cuando se le pasa al programa hace que el
se vuelva
y tu código nuevo se use. Lo subes, nadie se queja, tú puedes empezar a usar el programa de la manera nueva, el resto de gente puede ir migrando poco a poco y todo el mundo es feliz.
Ahora han pasado seis meses, tu funcionalidad nueva ya no es un experimento y se ha decidido que esto es lo que el programa debería hacer por defecto porque es mucho mejor que lo anterior y tenéis ya seis meses de experiencia usándolo que lo avalan. Lo que quieres ahora es que el programa por defecto haga la cosa nueva y si eso que opcionalmente se le pueda decir que use el código viejo, por si acaso, para mantener la compatibilidad para los más rezagados. De repente te encuentras con que hacer esto no es tan fácil como cambiar el
por defecto a
y ya. Porque en ese caso tienes que por defecto es
y si usas el parámetro
es... ¿también
? Algo no encaja. Así que decides cambiarle el nombre a tu parámetro y llamarlo
, para que se entienda que por defecto se va a hacer la cosa nueva y si eso la puedes desactivar a mano. Lo subes y ahora empiezan a llegar los mensajes enfadados. Resulta que la gente que hasta ahora sí a migrado a usar la cosa nueva, la gente que en principio querría tu cambio, es la gente que tiene por ahí decenas de scripts en los que están usando
. Scripts que ahora de repente se han roto, por lo que están muy enfadados porque has roto sus automatizaciones. Si tenéis todo en un mismo repositorio, ahora te toca a ti averiguar todos los sitios donde se usaba tu parámetro y cambiarlos a mano. Si no, ahora toca comunicar para que la gente cambie su código, lo que va a ser un proceso engorroso. En mitad del caos te planteas que a lo mejor quieres seguir manteniendo el parámetro viejo también aunque no haga nada sólo para evitar romper a la gente, al menos durante un tiempo, lo que es una chapuza pero es mejor que estar recibiendo notificaciones porque has roto algo que a lo mejor ni sabías que existía.
Imaginemos un escenario alternativo. En vez de hacer que
implícitamente signifique que quieres activar la nueva funcionalidad, has decidido que hay que pasarle el parámetro a mano. Hay que hacer algo tipo
o
. Ahora cambiar el valor por defecto sí es tan simple como cambiar el
interno del código de
a
. Toda la gente que no estaba usando ningún parámetro pasará a tener la cosa nueva y toda la gente que estaba usando
seguirá teniendo el mismo comportamiento. El valor por defecto cambia pero la interfaz no, así que no se rompen los scripts de nadie.
Hay veces en las que es bastante fácil predecir que el comportamiento por defecto de un programa siempre va a ser X y no va a cambiar nunca. Cosas como herramientas de debug, modos que se salten validaciones o supriman el output... En este caso es bastante razonable que se haga la cosa típica que explicábamos al principio, con el valor
por defecto y un argumento que lo convierte en
. Para el caso concreto de funcionalidad nueva en la que se está trabajando pero no se quiere activar por defecto todavía, es altamente probable que en el futuro termine siendo parte de la funcionalidad normal del programa. En este caso, creo que es buena idea obligar a especificar el valor del parámetro porque es probable que el comportamiento por defecto cambie en el futuro y en ese caso te ahorraras unos cuantos dolores de cabeza si lo haces así.