Многие системы используют диспетчеры событий, и их количество только увеличивается. Но долгое время они меня беспокоили. Я никогда не мог понять это, но я всегда чувствовал, что слишком много раз мне приходилось копаться в ошибке или функции, и я чувствовал, что фреймворк или система событий приложения борются против меня.

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

Например, чтение контроллера, который говорит следующее:

Кажется довольно очевидным, что этот контроллер принимает некоторые данные для нового пользователя, создает этого пользователя, а затем показывает вам страницу «спасибо за регистрацию», верно?

Но знаете ли вы, что он также отправил приветственное письмо пользователю? Готов поспорить, что нет. Я бы точно не стал. Но это могло бы объяснить, откуда пришли жалобы на перегрузку почтового сервера. Это также объясняет, почему мы получаем запутанные сообщения от пользователей о том, что их приветствуют после того, как они были членами в течение многих лет. Мы проследили это до того, как новый разработчик перенес пользователей со вторичной системы на эту, запустив некоторый код:

(Очевидно, что приведенное выше — всего лишь пример, а не приглашение к разговору о том, как вы должны протестировать это, прежде чем делать это вживую.)

Так, что происходит?

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

Когда миграция выполнялась и в базу данных добавлялось множество новых записей, каждая из них запускала приветственное письмо. Но это были не новые пользователи, это были существующие пользователи из другой базы данных.

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

Отличие событий от действий

Когда я говорю «это не одно и то же», я имею в виду, что техническая задача сохранения записи в базе данных — это не то же самое, что бизнес-задача создания новой учетной записи пользователя. Эти две вещи часто объединяют, потому что на первый взгляд они действительно выглядят как одно и то же.

Чтобы убедиться, что это не так, рассмотрим следующее:

Вы должны перейти от хранения ваших пользователей в вашей локальной базе данных к их хранению во внешней системе, выполнив вызов API. Потребует ли это изменение от вас повторной реализации событий, связанных с созданием нового пользователя, таких как отправка приветственного письма? Или ваша новая реализация будет запускать такое же событие «record created», которое теперь больше не описывает происходящее? Что бы вы ни делали, если вы подключались к событию создания записи в вашей базе данных, теперь вам нужно выполнить некоторый рефакторинг.

Проблема, похоже, в том, что в этом случае приветственное письмо должно быть связано с бизнес-действием по созданию учетной записи пользователя. Не к технической задаче вставки записи в базу данных.

Почему мы это делаем?

Так что же тогда вызывает эту проблему? Конечно, я не могу быть уверен (я не умею читать мысли), но я думаю, что в целом происходит то, что первое, что мы делаем, когда у нас есть новая функция, такая как «сохранение пользователя», мы делаем контроллер, который создает запись в базе данных. .

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

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

так что нам делать?

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

Чтобы пользователь мог создать учетную запись, мы должны сохранить его запись в базе данных иотправить ему электронное письмо.

Поскольку эти две технические задачи не связаны между собой, нам необходимо перенести ответственность на новый объект, связанный с бизнесом. Я выбрал имя ActionList, хотя это просто мой собственный выбор.

Интересно, что ActionList — это почти то же самое, что и Event. Другие части вашей системы регистрируются в нем и будут уведомлены, когда произойдет Действие. Настоящих отличий всего два:

  1. Действие — это строго событие, связанное с бизнесом. Ничего технического об этом.
  2. Поскольку действие строго связано с бизнесом, оно абсолютно ничего не делает само по себе.

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

К этому событию вы подключаете как метод вставки вашей системы сущностей, так и ваше приветственное письмо. (И ваше обновление статистики «количество учетных записей в системе», ваша статистика «новых регистраций сегодня» и все, что вы можете придумать)

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

Технические фрагменты кода больше не выполняют обязанности, которые вообще не связаны с этой обязанностью. Больше не происходит сбой при обновлении записи базы данных из-за того, что почтовый сервер не отвечает.

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