Сервис системы уведомлений. Как правильно спроектировать?

Обсуждаем, как правильно строить приложения
Ответить
myks1992@mail.ru
Сообщения: 147
Зарегистрирован: 2017.11.15, 23:54

Сервис системы уведомлений. Как правильно спроектировать?

Сообщение myks1992@mail.ru »

Всем привет!

Может ли кто подсказать как лучше реализовать на PHP + PostgreSQL независимый модуль системы уведомлений. Что будет:

1. Разные типы: комментарии, лайки и т д.
2. Разные каналы доставки: веб, email, смс
3. Возможность пользовательской настройки уведомлений какие типы куда отсылать. Например, комментарии на почту, лайки в веб.
4. Возможность разрешённых каналов доставки по типам

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

Хочу сделать более менее уверсально, чтобы можно было перетаскивать из проекта в проект. Возможно выделить вообще в отдельный веб сервис с API

Составил диаграмму БД: https://dbdiagram.io/d/5f5f44b27da1ea736e2dc266

1. Подскажите что тут не так?
2. Какие термины выбраны не очень правильно?
3. Сейчас сделана возможность подписки по типам, которые мы задали. А как сделать, чтобы можно было подписаться на определённую тему в форуме исходя из моей схемы? Сейчас не очень понимаю как это должно выглядеть. Спасибо за помощь!)
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Сервис системы уведомлений. Как правильно спроектировать?

Сообщение skynin »

примерно так и реализовать.

в моем текущем проекте похоже, но более унифицировано, для простоты обработки

есть направления рассылки.
есть виды сообщений (Поздравляем с днем рождения! Появился новый товар. У нас акция ..., и т.п.)
есть шаблоны сообщений, с простеньким макроязыком, по сочетанию направление - вид сообщения, чтобы по емайл - слать html письмо, а смской - короткий текст.
есть и настройки подписок пользователем. Пользователь может выбрать по какому направлению какой вид сообщений хочет получать. Может отписаться вообще от какого вида сообщений. И настройки по умолчанию

для хранения отосланных сообщений - используется одна таблица. Посмотрите внимательно, на ваши таблицы notification_notify они ведь почти не отличаются. В универсальной таблице просто еще две колонки direct_id, event_id.
Ну и по опыту - сразу сделана защита от повторной отсылки - хеш сообщения. Обязательно хоть раз произойдет когда из-за бага - запустится повторная рассылка. В комьютерные новости и истории на хабре постоянно такие случаи попадают :)

В итоге код работы у нас с такой системой простой

Произошло какое-то событие - запускается рассылка
а внутри уже определяется кому по какому направлению слать, и слать ли вообще, может отписался. А может уже отсылался этот текст

-- чтобы можно было подписаться на определённую тему в форуме исходя из моей схемы
вид сообщения плюс id темы
шаблон - по виду сообщения "Сообщения темы"

в настройках подписок пользователя нужно будет добавить кроме
direct_id, event_id. еще и какой-то entity_id. Если кроме тем форума еще что-то будет, то и group_id (из notification_groups)

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

Ну и еще по вашей схеме
как-то много varcharовых полей, хотя там целочисленные ID просятся.
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Сервис системы уведомлений. Как правильно спроектировать?

Сообщение skynin »

Отдельно примеры таблиц у нас, на MariaDB

Сами сообщения. У нас еще есть возможность пользователям писать другим пользователям приватные сообщения. И направление "сообщения в кабинете" пользователя.
А таблица вот одна на все напраления и виды событий:

Код: Выделить всё

CREATE TABLE `ss_letter` (
	`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`r_status` TINYINT(3) DEFAULT NULL AS (coalesce(cast(json_unquote(json_value(`ext_info`,'$.status')) as unsigned),0)) virtual,
	`event_id` INT(11) NOT NULL,
	`direct_id` INT(11) NOT NULL,
	`user_id` INT(10) UNSIGNED NOT NULL,
	`uniq_stamp` VARCHAR(64) NOT NULL COLLATE 'utf8_general_ci',
	`from_user` INT(10) UNSIGNED NOT NULL DEFAULT '1',
	`r_name` VARCHAR(250) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
	`r_text` TEXT(65535) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
	`created_at` TIMESTAMP NOT NULL DEFAULT current_timestamp(),
	`updated_at` TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
	`ext_info` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE INDEX `USERSTAMP_IDX` (`user_id`, `uniq_stamp`) USING BTREE,
	INDEX `updated_at` (`updated_at`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
Подробности, частности связанные с направлением или событием - в ext_info - это JSON поле, в MariaDB оно эмулируется.

Мелких таблиц не люблю, поэтому все остальное в одной таблице:

Код: Выделить всё

CREATE TABLE `ss_notify_dictionary` (
	`id` SMALLINT(5) UNSIGNED NOT NULL,
	`ent_kind` TINYINT(3) UNSIGNED NOT NULL,
	`ent_code` VARCHAR(250) NOT NULL COLLATE 'utf8_general_ci',
	`r_name` VARCHAR(250) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
	`r_text` TEXT(65535) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
	`event_id` SMALLINT(5) UNSIGNED ZEROFILL NULL DEFAULT NULL,
	`direct_id` SMALLINT(5) UNSIGNED ZEROFILL NULL DEFAULT NULL,
	`r_status` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
	`ext_info` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
	`updated_at` TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
	PRIMARY KEY (`id`, `ent_kind`) USING BTREE,
	UNIQUE INDEX `ent_code_idx` (`ent_code`, `ent_kind`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=Aria
;
Подробности там же, в JSON поле (шаблон, специфические флаги)

На уровне ORM просто разные классы, которые знают свой ent_kind - это направление, шаблон, группа, или еще что-то.

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

А настройки подписок пользователя - у нас тоже в JSON поле его записи :)
По быстродействию проблем пока нет. но думаю будут, когда счет им пойдет на сотни тысяч, миллионы.
Тогда отдельная таблица, с схемой как писал выше.
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
myks1992@mail.ru
Сообщения: 147
Зарегистрирован: 2017.11.15, 23:54

Re: Сервис системы уведомлений. Как правильно спроектировать?

Сообщение myks1992@mail.ru »

есть направления рассылки.
есть виды сообщений (Поздравляем с днем рождения! Появился новый товар. У нас акция ..., и т.п.)
А разве рассылка и уведомления не разные вещи?) Вот как раз то, что вы говорите это похоже на рассылку. И рассылка тоже может сильно разрастаться, а так же у неё другие задачи. Появился новый товар - уведомление, Новая акция - новость с уведомлением или рассылка. Мне так кажется или нет?)
есть шаблоны сообщений, с простеньким макроязыком, по сочетанию направление - вид сообщения, чтобы по емайл - слать html письмо, а смской - короткий текст.
Да, шаблоны у меня тоже будут отдельно. Здесь их почему-то не добавил. Об этом уже думал.
для хранения отосланных сообщений - используется одна таблица. Посмотрите внимательно, на ваши таблицы notification_notify они ведь почти не отличаются. В универсальной таблице просто еще две колонки direct_id, event_id

Думал над объединением таблиц и сделать одну таблицу более универсальной. Подумав, решил обратное. Помимо браузера, почты, смс могут быть и другие каналы: чат, push. А в каждых из этих каналах могут быть разная архитектура и функционал. Сейчас я добавил только примитивные поля, нужные в большинстве случаев, но в push могут добавиться, например, иконка. В общем в этом вопросе я не до конца для себя решил на сколько оправдан такой подход.
Ну и по опыту - сразу сделана защита от повторной отсылки - хеш сообщения. Обязательно хоть раз произойдет когда из-за бага - запустится повторная рассылка. В комьютерные новости и истории на хабре постоянно такие случаи попадают :)
У меня Хэш может быть UUID, который и будет уникальным)
Произошло какое-то событие - запускается рассылка
Заметил, что вы всё время говорите про рассылку. Разве это одно и то же?) Уведомления могут быть мгновенными, а могут быть с задержкой. В дальнейшем буду делать даже как часто уведомлять. Но опять акцентирую — уведомления и рассылка разве не разные системы?
notification_recipients - не нужны.
Вот тут всё таки спорно) Я делаю независимый модуль и не хотел бы зависеть от данных модуля User. Поэтому хотел при регистрации в USER создавать новые данные в notification_recipients c phone и email. Кроме того это позволит присылать уведомления на другой телефон или email, который захочет пользователь.
При появлении новой "темы форума" - прописывать каждому что он подписался

Разве подписчики темы и уведомления не разные вещи?) Follower - это последователь, который не обязательно должен получать уведомления. А вот в уведомлениях он уже может указать флаг "присылать уведомления о новых сообщениях в теме". Я думал тоже что это разные вещи. Нет?)
Если пользователей миллионы, то делать в обратку - кто НЕ отписался - тот подписан. Или еще как добавлять вычисление условия подписки на лету.
Пользователей не миллионы, но, хорошая идея, если вдруг будут нагрузки
Ну и еще по вашей схеме
как-то много varcharовых полей хотя там целочисленные ID просятся.
Такие поля делаются для понимания и читабельности)) например, что в колонке status будет значить 1? Никто не знает? А 2? Не имея кода не понять. У меня проект не нагруженный, поэтому могу себе позволить использовать нормальные читабельные поля для status: new, done, reject, error... Вместо автоикремента будут UUID, поэтому много текстовых полей...
Но это уже вкусовщина, сводить все в dictionary (meta) таблицы, по книжке обычно делают разными таблицами, как у вас. не суть важно.
смотря какие словари)) Но ничего такого тут нет.
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Сервис системы уведомлений. Как правильно спроектировать?

Сообщение skynin »

myks1992@mail.ru писал(а): 2020.09.14, 23:52 А разве рассылка и уведомления не разные вещи?)
Хотите делайте одинаковыми, хотите - разными
Это все слова.
myks1992@mail.ru писал(а): 2020.09.14, 23:52 Появился новый товар - уведомление, Новая акция - новость с уведомлением или рассылка.
Вы путаетесь в словах.

Ок.
Есть информация которую нужно доставить пользователю.
А уж как ее донести, хоть робот пусть звонит на телефон.

Так вот этот пакет информации не вижу смысла как-то обрабатывать по особому, потому что для компьютера нет никакой разницы между "новыми акциям", "уведомлениями", ...,
это просто набор байт, с адресом доставки. В адрес доставки, с точки зрения компьютера входит и канал доставки и адресат.
Мало того, у меня система рассылки работает с несколькими smtp сервисами. Решая по разным критериям какой выбрать для вот этого емайл сообщения. по смс тоже самое, шлюз не один. Но это транспортный уровень, в данном контексте можно опустить.
myks1992@mail.ru писал(а): 2020.09.14, 23:52 Подумав, решил обратное. Помимо браузера, почты, смс могут быть и другие каналы: чат, push.
Дело хозяйские. Хоть для каждого пользователя свою таблицу можно заводить.

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

У меня критерии - простота, единообразность, универсальность.
Добавить в мое решение еще хоть какие чудные направление пару констант в словарь, да может класс отнаследовать.
И все. Админка работает, рассыльщик работает.
myks1992@mail.ru писал(а): 2020.09.14, 23:52 но в push могут добавиться, например, иконка.
Это в шаблоне. к механизму доставки сообщений не имеет отношения.
Максимум - статус сообщения, может иметь разное отображение
myks1992@mail.ru писал(а): 2020.09.14, 23:52 У меня Хэш может быть UUID, который и будет уникальным)
Если UUID не связан с содержимым - он никак не решает проблему:
Систему заклинило и она вызывает подсистему рассылки:
Разошли оповещение об акции
Новогодняя скидка!

Не имея хеша на "Новогодняя скидка!" - подсистема рассылки никак не проверит что 5 минут тому отсылала уже это оповещение.

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

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

Рисковое решение - идентификация сущности в системе = содержимое этой сущности. Но, дело хозяйское, уверены что так надо - делайте :)
myks1992@mail.ru писал(а): 2020.09.14, 23:52 Такие поля делаются для понимания и читабельности)) например, что в колонке status будет значить 1? Никто не знает? А 2?
Ну, если пользователи или операторы у вас читают SQL, сами пишут SQL запросы то конечно, это важно.

А так, извините, ерунда какая-то, про "читабельность значений в БД" я до вас ничего не слышал :)

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

У меня в админке просто есть средства просмотра, поиска, фильтрации сообщений.
У вас наверное не подразумевается такого UI, и нужно будет вручную SQL запросы писать? тогда наверное да.
Но я правда и в таких случаях просто джойню к словарю.

Но, как хотите так и делайте.
myks1992@mail.ru писал(а): 2020.09.14, 23:52 что вы всё время говорите про рассылку. Разве это одно и то же?)
Или вы сами не понимаете о чем говорите :)
myks1992@mail.ru писал(а): 2020.09.14, 23:52 Разве подписчики темы и уведомления не разные вещи?)
Путаетесь в словах :)

Для системы рассылки уведомлений нет никакой разницы.
Есть текст, его нужно доставить пользователю. И все.
За кому нужно - отвечает механизм подписки, как нужно - механизм направлений, каналов, и т.п.
Между уведомлением об акции, отказе в оформлении счета на покупку, поздравлением с днем рождения, сообщением о новом посте в теме, емайлом с токеном подтверждения смены пароля, кодом подтверждения операции по смс, ..., ..., ... - нет никакой разницы по сути.
Подписчик темы это всего лишь пользователь, который там чего-то. Это чего-то систему рассылки уже не интересует.
Сообщение - уведомление - в чем разница то? Для системы рассылки - в чем между ними разница?
Кому доставить, Что доставить, посредством Чего (Какими способом) доставить.
Вот три базовые вещи системы рассылок.
Любой.
Остальное - детали.

Абстрагируйтесь от деталей.

На остальное не вижу смысла отвечать - оценки своего решения, которое работает на этом проекте уже больше года, и подобное работает еще на двух я не заказывал.
Это у вас был вопрос, как сделать. У меня не было :) Погуглил чуть, да и сделал. Нужных не нашел, либо простенькие совсем, либо переусложненные с малопонятной мне целью, либо являющие неотделимой частью от остального проекта, CMS, форумного движка, или завязанные на фреймворк (портировать из Laravel например непросто)

Делайте как хотите, а я всего лишь рассказал как я делаю, на основе опыта разработки и поддержки таких решений.
myks1992@mail.ru писал(а): Вместо автоикремента будут UUID, поэтому много текстовых полей...
ну да, одно неверное решение имеет последствиями другие неверные решения :)
Как там, кажется у Гете - сютрук не получится застегнуть правильно, если первая пуговица застегнута неправильно.

Зачем вам UUID?
Не, бывает нужен конечно именно UUID.
Но БД так устроены что они его не любят.

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

но надо, вот прям надо и все тут - значит да, делайте с UUID
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
myks1992@mail.ru
Сообщения: 147
Зарегистрирован: 2017.11.15, 23:54

Re: Сервис системы уведомлений. Как правильно спроектировать?

Сообщение myks1992@mail.ru »

skynin писал(а): 2020.09.15, 09:21
myks1992@mail.ru писал(а): 2020.09.14, 23:52 А разве рассылка и уведомления не разные вещи?)
Хотите делайте одинаковыми, хотите - разными
Это все слова.
myks1992@mail.ru писал(а): 2020.09.14, 23:52 Появился новый товар - уведомление, Новая акция - новость с уведомлением или рассылка.
Вы путаетесь в словах.

Ок.
Есть информация которую нужно доставить пользователю.
А уж как ее донести, хоть робот пусть звонит на телефон.

Так вот этот пакет информации не вижу смысла как-то обрабатывать по особому, потому что для компьютера нет никакой разницы между "новыми акциям", "уведомлениями", ...,
это просто набор байт, с адресом доставки. В адрес доставки, с точки зрения компьютера входит и канал доставки и адресат.
Мало того, у меня система рассылки работает с несколькими smtp сервисами. Решая по разным критериям какой выбрать для вот этого емайл сообщения. по смс тоже самое, шлюз не один. Но это транспортный уровень, в данном контексте можно опустить.
myks1992@mail.ru писал(а): 2020.09.14, 23:52 Подумав, решил обратное. Помимо браузера, почты, смс могут быть и другие каналы: чат, push.
Дело хозяйские. Хоть для каждого пользователя свою таблицу можно заводить.

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

У меня критерии - простота, единообразность, универсальность.
Добавить в мое решение еще хоть какие чудные направление пару констант в словарь, да может класс отнаследовать.
И все. Админка работает, рассыльщик работает.
myks1992@mail.ru писал(а): 2020.09.14, 23:52 но в push могут добавиться, например, иконка.
Это в шаблоне. к механизму доставки сообщений не имеет отношения.
Максимум - статус сообщения, может иметь разное отображение
myks1992@mail.ru писал(а): 2020.09.14, 23:52 У меня Хэш может быть UUID, который и будет уникальным)
Если UUID не связан с содержимым - он никак не решает проблему:
Систему заклинило и она вызывает подсистему рассылки:
Разошли оповещение об акции
Новогодняя скидка!

Не имея хеша на "Новогодняя скидка!" - подсистема рассылки никак не проверит что 5 минут тому отсылала уже это оповещение.

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

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

Рисковое решение - идентификация сущности в системе = содержимое этой сущности. Но, дело хозяйское, уверены что так надо - делайте :)
myks1992@mail.ru писал(а): 2020.09.14, 23:52 Такие поля делаются для понимания и читабельности)) например, что в колонке status будет значить 1? Никто не знает? А 2?
Ну, если пользователи или операторы у вас читают SQL, сами пишут SQL запросы то конечно, это важно.

А так, извините, ерунда какая-то, про "читабельность значений в БД" я до вас ничего не слышал :)

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

У меня в админке просто есть средства просмотра, поиска, фильтрации сообщений.
У вас наверное не подразумевается такого UI, и нужно будет вручную SQL запросы писать? тогда наверное да.
Но я правда и в таких случаях просто джойню к словарю.

Но, как хотите так и делайте.
myks1992@mail.ru писал(а): 2020.09.14, 23:52 что вы всё время говорите про рассылку. Разве это одно и то же?)
Или вы сами не понимаете о чем говорите :)
myks1992@mail.ru писал(а): 2020.09.14, 23:52 Разве подписчики темы и уведомления не разные вещи?)
Путаетесь в словах :)

Для системы рассылки уведомлений нет никакой разницы.
Есть текст, его нужно доставить пользователю. И все.
За кому нужно - отвечает механизм подписки, как нужно - механизм направлений, каналов, и т.п.
Между уведомлением об акции, отказе в оформлении счета на покупку, поздравлением с днем рождения, сообщением о новом посте в теме, емайлом с токеном подтверждения смены пароля, кодом подтверждения операции по смс, ..., ..., ... - нет никакой разницы по сути.
Подписчик темы это всего лишь пользователь, который там чего-то. Это чего-то систему рассылки уже не интересует.
Сообщение - уведомление - в чем разница то? Для системы рассылки - в чем между ними разница?
Кому доставить, Что доставить, посредством Чего (Какими способом) доставить.
Вот три базовые вещи системы рассылок.
Любой.
Остальное - детали.

Абстрагируйтесь от деталей.

На остальное не вижу смысла отвечать - оценки своего решения, которое работает на этом проекте уже больше года, и подобное работает еще на двух я не заказывал.
Это у вас был вопрос, как сделать. У меня не было :) Погуглил чуть, да и сделал. Нужных не нашел, либо простенькие совсем, либо переусложненные с малопонятной мне целью, либо являющие неотделимой частью от остального проекта, CMS, форумного движка, или завязанные на фреймворк (портировать из Laravel например непросто)

Делайте как хотите, а я всего лишь рассказал как я делаю, на основе опыта разработки и поддержки таких решений.
myks1992@mail.ru писал(а): Вместо автоикремента будут UUID, поэтому много текстовых полей...
ну да, одно неверное решение имеет последствиями другие неверные решения :)
Как там, кажется у Гете - сютрук не получится застегнуть правильно, если первая пуговица застегнута неправильно.

Зачем вам UUID?
Не, бывает нужен конечно именно UUID.
Но БД так устроены что они его не любят.

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

но надо, вот прям надо и все тут - значит да, делайте с UUID
Вы не подумайте, что я пытаюсь Вас как-то обидеть) Просто разбираюсь в вопросе, а не пытаюсь вас упрекнуть) Вопрос задал в Архитектуру, потому что мне она важна. Понимаю, что в Yii чаще не преследуют проектирование архитектуры, а используют RAD подход. Вы сказали, что для компьютера код без разницы какой. Согласен, но хороший код пишут для людей) Чтобы потом не разбираться что там было записано, а читать код как книжку. Понимаю ваш подход прекрасно и нисколько не оспариваю Ваш выбор)

Скажите ещё для уточнения. Ваши уведомления все в одной таблице. Верно? И как вы разделяете шаблоны? Они тоже одни для смс, email и так далее...?
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Сервис системы уведомлений. Как правильно спроектировать?

Сообщение skynin »

-- Понимаю, что в Yii чаще не преследуют проектирование архитектуры, а используют RAD подход
Зависит от размера-сложности проекта
И от квалификации программиста. Скажем, новичек после нескольких проработок курсов на Ютьюбе по другому просто не умеет.
Он еще некомпетентен в вопросах выбора архитектуры.

Если же знать несколько видов, подходов к архитектуре, понимать их, попробовать И посмотреть каким боком вылазят через годик-два развития проекта недостатки выбранной архитектуры (а они есть у каждой) - то Yii2 очень гибкий, мешать применять их не будет.

-- Ваши уведомления все в одной таблице. Верно? И как вы разделяете шаблоны?
Шаблоны не имеют отношения к хранению и доставке сообщений.

У меня они хранятся в словаре. И привязаны к паре - событие-направление

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

- В системе имеется событие, о котором надо оповещать.
- Система генерирует событие
- Детектор заинтересованных получателей подписан на события системы. И получив, формирует список получателей, вычеркивая отписавшихся вообще.
- Передает этот список формирователю сообщений
- Формирователь сообщений для каждого получателя смотрит на направление подписки, выбирает для событие-направление нужный шаблон, вставляет данные события в шаблон, и получив конечный вариант сообщения передает его рассыльщику
- Рассыльщик про шаблоны уже ничего не знает, он получает уже готовое для отсылки сообщение. Проверяет его по хешу, кладет в базу, и вызывает транспортировщика
- Транспортировщик смотрит на направление и вызывает соответствующего направлению доставщика. Который и осуществляют доставку сообщения обращаясь к внешнему миру, и записывают нужную транспортную инфу в ext_info сообщения (о сбоях, количестве попыток, и прочее что нужно, если оно нужно ему, или для анализа, отладки потомм)

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

Хранение же в БД должно выбираться несколько по другим критериям, и в общем случае - никак не связано с архитектурой приложения.
Утрировано - можно вообще все данные системы хранить в одной таблице, с кучей колонок :)
Можно - даже для пользователей создать таблиц по количеству букв алфавита, и выбирать таблицу по первой букве емайла пользователя (при смене емайла ессно перемещать).
А как надо? кто его знает, как вам надо, вы проектируете, вам лучше знать :)

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

Если с этим сложности, а сколько не встречаю в жизни, люди и программисты не могут ответить на вопрос - Зачем, С какой целью, тогда надо делать "как все" и не выпендриваться с проектированием. Выбрать авторитетную книгу, или проект из нее и брать - как сделать. Будет наверное неэлегантное решение, но - неплохое.
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Сервис системы уведомлений. Как правильно спроектировать?

Сообщение skynin »

Итоги, отдельно

Проектирование в ООП - это написание должностных инструкций для работников - кто за что отвечает. Чем меньше ответственности получится у каждого исполнителя, тем лучше. Гуглить "Принцип единственной ответственности" https://ru.wikipedia.org/wiki/%D0%9F%D1 ... 1%82%D0%B8
Ессно этот принцип можно и нужно нарушать когда это можно и нужно :D Когда есть четкий ответ - почему его нужно нарушить в каком-то случае.

А у проектирования хранения данных - соовсем другое важно. Их надо хранить так, чтобы потом максимально эффективно и просто можно было с ними работать. То есть чтобы выбрать схему БД - нужно вначале ответить на вопросы - а что мы потом чаще всего будем делать с этими данными.
Просто - не с точки зрения человека, человек обычно напрямую с этими данными уже не работает ;)

То есть это не связанные, а нередко входящие в противоречие подходы.

В простых же случаях можно просто прибивать гвоздями классы к таблицам да и все.
То есть проектировать от объектов приложения. А схему развитые ORM даже сами сгенерят, по аннотациям классов

Я к тому что у вас и на это должен быть четкий ответ:
Почему вы начали проектировать систему рассылки с схемы таблиц, а не с "написания должностных инструкций" для классов системы

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

Правильных ответов нет.
Правильно - это когда есть четкий ответ, а неправильно, когда нуууу, я... это...
Не желайте странного, и не будет у вас головной боли чтобы достичь этого странного.
Тем более что окажется что оно вам и не нужно было, странное это.
skynin
Сообщения: 400
Зарегистрирован: 2017.12.12, 10:09

Re: Сервис системы уведомлений. Как правильно спроектировать?

Сообщение skynin »

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

"Не так важно что умеет делать ваша программа сегодня. Важнее что она будет уметь делать завтра" (кажется Стив Макконелл )

Как перестать быть джуниором и начать жить:
1. Научиться программировать
В понятие «уметь программировать» входит не только знание конкретного языка программирования. Базовые профессиональные умения программиста должны включать следующие пункты:
Формализация задачи — это умение разложить ее на составляющие и сформулировать так, чтобы ее можно было написать в виде программного кода.
Проектирование — способность представить архитектуру решения, понимание того, чего вы хотите достичь и каким образом это можно сделать.
Написание кода.
Понимание кода — умение читать и понимать написанное кем-то другим.
Рефакторинг кода — умение увидеть ошибки и недостатки кода и переписать его так, чтобы он работал лучше и был более поддерживаемым. Это высшая форма деятельности программиста, потому что это умеет делать только тот, кто программирует по-настоящему хорошо.
https://skillbox.ru/media/code/kak_pere ... zhuniorom/

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

А мимодумно писать код да, дело нехитрое :)
Чем большинство с званием программист и занимаются.
Прислали тут, очередное "творение"...

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

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