Siempre he tenido dudas a la hora de diseñar informes de ejecución adecuados.Información de informes durante la ejecución del código: mejor diseño
Digamos que tiene el siguiente caso (estúpido, para ser simple). Usaré Python.
def doStuff():
doStep1()
doStep2()
doStep3()
Ahora, supongamos que desea dar un informe de los distintos pasos, si algo va mal, etc. En realidad, no de depuración: simplemente el comportamiento informativo de la aplicación.
Una primera solución, fácil es poner impresiones
def doStuff():
print "starting doing stuff"
print "I am starting to do step 1"
doStep1()
print "I did step 1"
print "I am starting to do step 2"
doStep2()
print "I did step 2"
print "I am starting to do step 3"
doStep3()
print "I did step 3"
En general, esto es bastante malo. Supongamos que este código va a terminar en una biblioteca. No esperaría que mi biblioteca imprima cosas. Esperaría que hiciera el trabajo en silencio. Sin embargo, a veces me gustaría proporcionar información, no solo en situaciones de depuración, sino también para mantener al usuario informado de que algo realmente está en proceso de finalización. Imprimir también es malo porque no tienes control del manejo de tus mensajes. simplemente va a stdout, y no hay nada que puedas hacer al respecto, excepto la redirección.
Otra solución es tener un módulo para el registro.
def doStuff():
Logging.log("starting doing stuff")
Logging.log("I am starting to do step 1")
doStep1()
Logging.log("I did step 1")
Logging.log("I am starting to do step 2")
doStep2()
Logging.log("I did step 2")
Logging.log("I am starting to do step 3")
doStep3()
Logging.log("I did step 3")
Esto tiene la ventaja de que se sabe especie de un lugar único para su servicio de registro, y se puede retocar este servicio tanto como usted desee. Puede silenciarlo, redirigirlo a un archivo, a stdout, o incluso a una red. La desventaja es que obtiene un acoplamiento muy fuerte con el módulo de registro. Básicamente, cada parte de tu código depende de él, y tienes llamadas para iniciar sesión en cualquier lugar.
La tercera opción es tener un objeto de informe con una interfaz clara, y pasarlo alrededor
def doStuff(reporter=NullReporter()):
reporter.log("starting doing stuff")
reporter.log("I am starting to do step 1")
doStep1()
reporter.log("I did step 1")
reporter.log("I am starting to do step 2")
doStep2()
reporter.log("I did step 2")
reporter.log("I am starting to do step 3")
doStep3()
reporter.log("I did step 3")
Eventualmente, también puede pasar el objeto reportero a doStepX() si tienen más que decir. Ventaja: reduce el acoplamiento con un módulo, pero introduce el acoplamiento con la creación de instancias del objeto NullReporter. Esto se puede resolver mediante el uso de ninguno por defecto y comprobar antes de llamar a registro, que es torpe, porque en Python que tiene que escribir un condicional cada vez (en C se puede definir una macro)
def doStuff(reporter=None):
if reporter is not None:
reporter.log("starting doing stuff")
# etc...
Editar: Otro la opción es trabajar como Qt, y tener una estrategia de señal emit(). A medida que su código se ejecuta, emite información con códigos de estado adecuados, y cualquier persona interesada puede suscribirse a las señales y proporcionar información. Agradable y limpio, muy desacoplado, pero requiere un poco de codificación, ya que no creo que esto pueda hacerse rápidamente con la batería de pitón incluida.
Finalmente, puede plantear excepciones con un mensaje de error significativo, pero esto, por supuesto, se puede usar solo si sale de una condición de error. no funciona para informes ocasionales.
Editar: Me gustaría aclarar el hecho de que la situación es más general, y no se limita solo a una secuencia de pasos invocados. También podría considerar estructuras de control:
if disconnected:
print "Trying to connect"
connect()
else:
print "obtaining list of files from remote host"
getRemoteList()
El informe también podría ser en las rutinas reales, por lo que tendría una "impresión" en las rutinas connect() y getRemoteList() como un primer comunicado.Por lo tanto,
La pregunta es:
- Cuál cree usted que es el mejor diseño para un cierto código (especialmente en el caso de una biblioteca) que sea al mismo tiempo en silencio cuando el ruido puede ser perjudicial para el cliente , pero prolijo cuando es útil?
- ¿Cómo manejar una combinación equilibrada entre código lógico y código de informe?
- La mezcla entre códigos y la comprobación de errores se ha resuelto con excepciones. ¿Qué se puede hacer para dividir el "ruido" de informar desde la lógica del código?
Editar: más pensamientos de la mente
creo que es no sólo una cuestión de desacoplar el código de registro del código de la lógica. Creo que también se trata de disociar la producción de información del consumo de información. Ya existen técnicas similares, en particular para manejar eventos de IU, pero realmente no veo los mismos patrones aplicados al problema de registro.
Editar: acepté la respuesta de Marcelo porque señala a los elementos de hecho que un compromiso es la mejor solución en este caso, y no hay bala de plata. Sin embargo, todos los demás también fueron respuestas interesantes, y estuve muy contento de haberlos votado a todos. ¡Gracias por la ayuda!
He añadido una recompensa para ver si se puede seguir hablando sobre esta cuestión. Además, esta es la primera apertura de recompensas, así que también tenía curiosidad por hacerlo. –