Как их использовать и в чем разница?

Философия программирования Unix заключается в том, чтобы делать (только) одно, но делать это хорошо. Сосредоточиться на одной ключевой задаче сложно, поскольку разработчики видят и чувствуют болевые точки и желания своих пользователей. Чтобы иметь возможность сосредоточиться на основном продукте, но допустить дополнительные функции, о которых мы не можем заботиться, мы разрабатываем системы плагинов. Один из способов сделать это - использовать крючки.

Хук - это способ расширения программного обеспечения.

Подумайте о почтовом клиенте. Почтовый клиент может определить ловушку pre_send, которая получает текущего получателя, строку темы и содержимое электронного письма. Разработчики могут использовать это для расширения программного обеспечения. У вас может быть один плагин, который использует этот хук и добавляет подпись, если она отсутствует. Еще одна ловушка может найти нецензурную лексику и помешать вам отправить это письмо пьяным по ночам, о чем вы пожалеете.

Другой способ расширить программное обеспечение - это событие. Событие просто сообщает плагину, что что-то произошло. Хук может позволить вам остановить дальнейший поток выполнения - например, запретить отправку электронного письма с нецензурной лексикой.

Обратные вызовы

Обратные вызовы - это указатели на функции. Они представляют собой конкретную функцию.

Например, представьте себе поискового робота, который хочет получить содержимое many_urls. Вы можете запускать его последовательно:

for url in many_urls:
    get_content(url)

Или вы можете реализовать функцию, которая выполняет все параллельно для каждого аргумента:

parallel_for(get_content, many_urls)

Обратите внимание, что мы не вызываем get_content во втором примере. Мы передаем его как параметр функции. Когда вы передаете функцию в качестве параметра другой функции, вы вызываете ее обратным вызовом.

Обратные вызовы и хуки

Обратные вызовы могут использоваться для реализации ловушек. Если вы еще раз вспомните приведенный выше пример электронной почты, вы можете реализовать его следующим образом:

import email_client
email_client.register_pre_send_hook(add_signature)
email_client.register_pre_send_hook(detect_swearwords)

Разработчикам email_client необходимо предоставить метод register_pre_send_hook. Они должны сказать вам, что эта функция ожидает функцию в качестве параметра: обратный вызов.

Им нужно сказать вам, что они будут запускать каждый заданный обратный вызов следующим образом:

def send_email():
    # Execute all registered hooks
    for hook in registered_hooks:
        email = hook(email)

Итак, ваш хук получает объект email. Он может изменять этот объект любым способом и перезаписывать содержимое любым способом.

Вебхуки

Веб-перехватчики - это перехватчики, используемые в веб-сервисах. Как и в случае с обычными хуками, вы можете расширить функциональность веб-службы с помощью хуков. Например, Slack позволяет отправлять сообщения по URL-адресу (источнику).

Веб-перехватчики позволяют веб-сайтам передавать вам информацию вместо того, чтобы вы ее извлекали (и опрашивали).

Давайте конкретизируем. Вы наверняка пользуетесь Slack. А может быть, у вас есть система мониторинга типа Sentry. Теперь вы хотите, чтобы сообщение Slack появлялось на определенном канале всякий раз, когда Sentry обнаруживает новую проблему.

Механизм опроса был бы прост - Slack каждые несколько секунд спрашивал Sentry, есть ли новое сообщение. Это потребует от Slack и Sentry гораздо больше ресурсов, чем необходимо. Вместо того, чтобы получать сообщения из Slack, мы хотим, чтобы Sentry отправлял сообщения в Slack.

Веб-серверы обычно не знают своих клиентов. Чтобы иметь возможность передавать информацию в Slack, это необходимо изменить. Клиент (Slack) должен подписаться на сервер (Sentry). Slack необходимо передать URL-адрес Sentry. Код на часовом может выглядеть так:

def subscribe(callback_url):
    # callback_url could be
    # https://hooks.slack.com/services/T000/B000/XXXXXXXX
    store_in_client_list(callback_url)

Обе стороны должны согласовать, какой формат использовать для обмена. В случае со Slack они предоставляют документацию для своей системы веб-перехватчиков. Обе стороны могут это сделать. В конце концов, имеет значение только то, что они согласны.

Когда Sentry обнаруживает новую проблему, они отправляют данные в Slack:

def handle_subscribers(event):
    subscribers = event.get_subscribers()
    for subscriber in subscribers:
        post(subscriber.callback_url, event.data)

Метод post также может использовать возвращаемое значение, но в случае Slack, насколько мне известно, оно просто игнорируется.

Резюме

  • Хук - это способ расширения программного обеспечения.
  • Обратный вызов - это функция, которая передается в качестве параметра другой функции.
  • Вебхук - это приманка в сети. Обычно используется для установления связи между двумя различными системами и, как правило, для перехода от опроса к модели издатель-подписчик.