У меня всегда были сомнения, когда речь шла о разработке надлежащего отчета об исполнении.
Скажем, у вас есть следующий (глупый, чтобы быть простым) случай. Я буду использовать Python.
def doStuff():
doStep1()
doStep2()
doStep3()
Теперь предположим, что вы хотите сообщить о различных шагах, если что-то идет не так и т. Д. Не совсем отладка: просто информативное поведение приложения.
Первое, простое решение - нанести отпечатки
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"
В общем, это довольно плохо. Предположим, что этот код окажется в библиотеке. Я не ожидал бы, что моя библиотека распечатает материал. Я ожидал бы, что это сделает работу тихо. Тем не менее, иногда я хотел бы предоставить информацию не только в ситуациях отладки, но и для того, чтобы пользователь был информирован о том, что что-то на самом деле находится в процессе выполнения. Печать также плохая, потому что вы не можете контролировать свои сообщения. он просто переходит на стандартный вывод, и с этим ничего нельзя поделать, кроме перенаправления.
Другим решением является наличие модуля для регистрации.
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")
Это имеет то преимущество, что вы как бы знаете уникальное место для вашей службы регистрации, и вы можете изменять эту службу столько раз, сколько захотите. Вы можете отключить его, перенаправить на файл, на стандартный вывод или даже в сеть. Недостатком является то, что вы получаете очень сильную связь с модулем регистрации. В основном от этого зависит каждая часть вашего кода, и у вас есть вызовы для ведения журналов везде.
Третий вариант - иметь объект отчета с понятным интерфейсом, и вы передаете его
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")
В конце концов, вы также можете передать объект-репортер в doStepX (), если им есть что сказать.
Преимущество: он уменьшает связь с модулем, но вводит связь с созданием объекта NullReporter. Это можно решить, используя None по умолчанию и проверяя перед вызовом log, что неуклюже, потому что в python вы должны писать условные выражения каждый раз (в C вы можете определить макрос)
def doStuff(reporter=None):
if reporter is not None:
reporter.log("starting doing stuff")
# etc...
Edit:
Другой вариант - работать в стиле Qt и иметь стратегию сигнала emit (). Когда ваш код выполняется, он генерирует информацию с соответствующими кодами состояния, и любой желающий может подписаться на сигналы и предоставить информацию. Хороший и чистый, очень отделенный, но требует немного кодирования, так как я не думаю, что это можно быстро сделать с включенной батареей питона.
Наконец, вы можете вызывать исключения с помощью значимого сообщения об ошибке, но это, конечно, можно использовать, только если вы выходите из состояния ошибки. он не работает для периодических отчетов.
Редактировать: Я хотел бы прояснить тот факт, что ситуация является более общей, и не ограничивается только последовательностью вызванных шагов. это может также включать контрольные структуры:
if disconnected:
print "Trying to connect"
connect()
else:
print "obtaining list of files from remote host"
getRemoteList()
Отчет также может быть в реальных подпрограммах, так что в качестве подпрограммы connect () и getRemoteList () в качестве первого оператора вы можете использовать «print».
Таким образом, вопрос таков:
- Как вы думаете, что является лучшим дизайном для некоторого кода (особенно в случае библиотеки), который должен быть в то же время тихим, когда шум может быть разрушительным для клиента, но многословным, когда полезно?
- Как обрабатывать сбалансированное смешивание между логическим кодом и кодом отчетности?
- Смешивание между проверкой кода и ошибок было решено с исключениями. Что можно сделать, чтобы отделить «шум» отчетности от логики кода?
Редактировать: больше мыслей для ума
Я думаю, что дело не только в том, чтобы отделить код логирования от логического кода. Я думаю, что это также вопрос отделения производства информации от потребления информации. Подобные методы уже существуют, в частности, для обработки событий пользовательского интерфейса, но на самом деле я не вижу тех же шаблонов, которые применяются к проблеме регистрации.
Редактировать: Я принял ответ от Марсело, потому что он указывает на фактические доказательства того, что компромисс является лучшим решением в этом случае, и нет серебряной пули. Тем не менее, все остальные тоже были интересными ответами, и мне было очень приятно отозвать их все. Спасибо за помощь!