¿Se considera un antipatrón leer de STDIN desde una biblioteca?

39

Mientras escribía una biblioteca para un gran proyecto en el que estoy trabajando en el trabajo, surgió un problema que requería que se enviara un token a una dirección de correo electrónico, y luego se volviera a pasar al código donde luego se puede usar para su uso posterior.

Mi colega dice que solo lea STDIN (usando Python:) code = input("Enter code: ")y luego haga que un usuario lo pase, sin embargo, para mí esto parece una mala práctica ya que la biblioteca podría (en este caso definitivamente) usarse en una tarea en segundo plano en un servidor .

Me preguntaba si esto se consideraba un antipatrón o no.

Paradoja
fuente
45
No todo lo malo es un "antipatrón", aunque ciertamente es malo.
Phoshi
44
"patrón" significa algo que los programadores hacen con frecuencia. Es solo un antipatrón si (A) es una mala idea y (B) es algo que ves que hacen los desarrolladores todo el tiempo.
Solomon Slow
20
Esto es demasiado tonto para ser un antipatrón. Un antipatrón es algo que parece natural y sensato, pero resulta ser malo cuando se profundiza en él. Lo que estás describiendo aquí es obviamente horrible.
Evan Harper
No veo el punto de ninguna de las respuestas. El objetivo del ejercicio de token de usuario debe ser demostrar que la dirección de correo electrónico del usuario funciona. Si ese no fuera el punto, entonces sería mucho más simple simplemente almacenar el token.
emory
2
Esto es bastante horrible Si es absolutamente necesario pasar un token como ese, puede hacer un ejecutable separado usando la biblioteca y pasar su token a su stdin. Pero secuestrar el stdin del ejecutable de llamada, eso es un no-no.
GrandmasterB

Respuestas:

78

Como pauta general, las bibliotecas deben estar totalmente desconectadas del entorno. Eso significa que no deben realizar operaciones en transmisiones estándar, en archivos específicos, ni tener ninguna expectativa sobre el entorno o el contexto en el que se utilizan.

Por supuesto, hay excepciones a esta regla, pero debe haber una muy buena razón para ello. En el caso de usar stdin, no puedo encontrar ninguna razón (a menos que su biblioteca realmente proporcione rutinas para leer desde stdin, como std::cindesde C ++). Además, tomar las secuencias de E / S de un parámetro en lugar de tenerlas codificadas agrega tanta flexibilidad que no vale la pena no hacerlo.

Paul92
fuente
36
La excepción es una biblioteca que tiene el objetivo específico de interactuar con un entorno. Incluso entonces, los detalles del entorno deben ser abstraídos. Por ejemplo, un controlador de gráficos tiene que comunicarse con el bus PCIe, pero la identificación del bus debe proporcionarse a través de la configuración.
Este es el tipo de excepción que pensé: mi idea estaba más cerca de ncurses , generalmente, una biblioteca de interfaz de usuario de entorno de texto. Si su propósito es leer la entrada del usuario y proporcionar la salida del usuario, esa es una buena razón.
SF.
55
@SF. Incluso una biblioteca como ncurses debería tomar un par de descriptores de archivo como argumentos en lugar de codificar el uso de 0 y 1. Es posible que desee escribir un programa donde se puedan redirigir stdin y stdout y, en su lugar, desee abrir /dev/ttypara comunicarse con el usuario. El programa podría incluso iniciarse sin un terminal y abrir su propio terminal usando xterm -S.
kasperd
3
@kasperd: El mejor enfoque es proporcionar valores predeterminados razonables y la capacidad de anularlos.
SF.
1
En este caso particular, no veo ninguna razón para exigir una secuencia como entrada. ¿Por qué no simplemente aceptar el token como parámetro?
jpmc26
16

Consideraría que esto no es necesariamente un antipatrón, solo una biblioteca mal diseñada. Debería ser trivial pedir una cadena como parámetro de método, donde la entrada podría pasarse directamente.

Si eso no se ajusta a este uso, entonces un parámetro del método puede ser una secuencia, con STDIN pasado al método.

Si eso no se ajusta a este uso, entonces la biblioteca no es lo suficientemente flexible.

Bryan Boettcher
fuente
4

Tal vez considere tener la capacidad en su biblioteca de establecer una devolución de llamada a una función proporcionada por el usuario que leerá la entrada desde cualquier lugar y luego devolverá el valor apropiado a cualquier parte de la biblioteca que esté usando esa función.

FrustratedWithFormsDesigner
fuente
1

Si lee de stdin, significa que le gustaría tomar posesión de stdin a nivel de programa. Es probable que no sea compatible con ninguna otra biblioteca que lea desde stdin, un protocolo menos específico sobre cómo comparten el uso. Al menos en mi propio glosario personal, esto convertiría a la biblioteca en un marco , lo cual es una compensación costosa.

Pero en este caso, la biblioteca probablemente solo debería tomar un descriptor de archivo de entrada.

djechlin
fuente
0

La respuesta de @ Paul92 es una buena discusión general, pero me gustaría ofrecer una posible solución limpia (ish) a esto:

Como una biblioteca, este código debe ser adaptable a cualquier entorno de tiempo de ejecución, por lo que realmente no puede solicitar STDINalgunos datos cruciales. Por un lado, los usuarios de su biblioteca podrían no tener stdin disponible por varias razones. En su lugar, es posible que desee utilizar algún tipo de patrón de estrategia para personalizar cómo se recuperará el token.

En Python, probablemente la mejor opción es pasar la estrategia de recuperación de tokens como un parámetro de función. Algo como eso:

def stdin_prompt():
    return input("Enter code: ")

def my_library_function(arg1, arg2, ... argn, token_provider = stdin_prompt):
    ...
    token = token_provider()
    ...
    return stuff

# somewhere in the user code
stuff = my_library_function(a1, a2, ... an, lambda: "123456")

Piensa en esto, de esta manera. El token que necesita es un argumento para la función de biblioteca. Dado que el valor del token puede no ser conocido estáticamente en el sitio de la llamada, realmente no puede solicitar el valor como argumento. En cambio, la persona que llama tiene que proporcionar una función que será responsable de proporcionar el token cuando se le llame.

Toda la responsabilidad de proporcionar la mecánica exacta del token ahora se externaliza desde la función de biblioteca. El consumidor de la función ahora es responsable de adquirir el token por cualquier medio disponible en tiempo de ejecución. Puede solicitar STDIN, pero también puede actuar como una puerta de enlace de correo, esperar a que el mensaje aparezca en la bandeja de entrada, leerlo, extraer el token y automatizar completamente el proceso. Puede ser un cuadro de diálogo GUI o un formulario basado en web. Cualquier cosa realmente: todas las opciones están ahora en manos del consumidor de la biblioteca.

Roland Tepp
fuente