#sql #ruby-on-rails #ember.js #devise #domain-driven-design
#sql #ruby-on-rails #ember.js #разработать #дизайн, управляемый доменом
Вопрос:
Итак, я хотел получить несколько советов о том, как правильно моделировать домен бизнес-логики.
Не вдаваясь в подробности NDA, я пытаюсь смоделировать относительно большую систему, которая включает проекты и людей (пока ничего слишком страшного). Прямо сейчас я создаю его в Rails, просто чтобы быстро получить что-то за дверью, но в конечном итоге я собираюсь переключить его на приложение Ember.js / JSON (не то, чтобы это действительно имело значение для этого вопроса).
Итак, в системе есть несколько разных типов «людей» — есть «пользователи» (люди, которые действительно могут войти в систему) и «контакты» (информация о людях, такая как номер телефона, адрес, электронная почта и т.д.). Единственная причина, по которой эти два разделены, заключается в том, что они логически различаются (контактная информация не требуется для входа в систему, и не каждому «контакту» потребуется информация для входа или он должен иметь ВОЗМОЖНОСТЬ войти в систему). Сразу возникает вопрос, имеет ли смысл разделять эти две сущности, или мне следует просто создать один широкий плоский объект со всеми полями для моделирования обоих логинов (и я имею в виду все поля, которые Devise добавляет сюда) и все поля для ввода контактной информации.
Кроме того, есть проекты. В проектах в качестве «контактов» используются люди разного уровня; в одном проекте «Фред» может быть ведущим или менеджером, а «Диана» — клиентом. Возможно (хотя и маловероятно), что в другом проекте «Диана» может быть ведущей, а «Фред» — другой ролью. Дело в том, что роли, которые каждый контакт играет в каждом проекте, изменчивы. Есть несколько ролей, которые НЕОБХОДИМО заполнить, чтобы проект был действительным (ну, не обязательно действительным, но активным).
Наконец, для разнообразия, приложение является многопользовательским. Таким образом, сама система имеет несколько «клиентов» (за неимением лучшего термина), у которых есть свои СОБСТВЕННЫЕ клиенты, и все данные клиентов (верхнего уровня) должны храниться строго разделенными.
Прямо сейчас, вот что я делаю:
- Почти у всего есть поле «customer_id», чтобы я мог охватывать все запросы (моих собственных) клиентов.
- Как упоминалось выше, «пользователи» (люди, которые могут входить в систему) и «контакты» (человек-полезная информация О людях) разделены. У одного «пользователя» должен быть один «контакт», но «контакты» не обязательно должны быть связаны с «пользователями» (в Rails я связываю это, говоря User belongs_to Contact). Это первое место, где я не уверен на 100%, что делаю это правильно.
- Проекты и контакты объединяются многие ко многим (через таблицу объединения), так что данный проект может иметь несколько контактов (и наоборот). Таблица соединений включает свойство «роль», чтобы я мог сказать, какую роль контакт играет в проекте. Это… работает, но это делает SQL очень неуклюжим (и я беспокоюсь, медленно). Правда, AREL управляет большей частью SQL для меня, но все же, чтобы получать приличные запросы (и избегать проблем N 1), мне приходится выполнять множество вызовов .joins /.includes, что для меня звучит как дырявая абстракция.
Итак, я оставлю это на этом и закончу тем, с чего начал: у кого-нибудь есть какие-либо советы о том, как правильно моделировать эту систему? Я даже приму ответы типа «чувак, это сложная система, но ты делаешь все, что в твоих силах». 🙂
Спасибо!
Комментарии:
1. Я думаю, что ваш вопрос слишком широк, и вы должны разделить его на конкретные проблемы. Для пункта 3 вы используете
has_many through:
? Я предполагаю, что вы, что означает, что использование большого количества соединений / включений, безусловно, является лучшим подходом для повышения эффективности.
Ответ №1:
Вот как я бы справился с этим…
Во-первых, диаграммы — это все! Может быть, вы это делали, а может и нет, но я всегда создаю диаграмму, показывающую всех различных участников (в данном случае пользователей, контакты, клиентов и заказчиков клиентов) и рисую их отношения.
Во-вторых, я бы не разделял пользователей и контакты. Что, если контакт становится пользователем? Что, если пользователь переходит к контакту? И т.д. и т.п. Это все вопросы, которые вы должны задать себе — те сценарии «что, если», которые, хотя сейчас они могут показаться маловероятными, могут возникнуть позже. Вы захотите, чтобы ваша система была максимально гибкой, если изменится вариант использования.
Итак, я бы создал таблицу «user» и предоставил им столбец привилегий. Этот человек — пользователь или контакт? Если человек является пользователем, сделайте контактную информацию необязательной, но если он является контактом, то она требуется, но он не может войти в систему. Кроме того, у вас, вероятно, должен быть другой вариант на случай, если пользователь является одновременно пользователем И контактом.
Тогда у меня была бы отдельная таблица «отношений» для варианта использования «многие ко многим» от клиентов к клиентам клиентов. Что-то вроде:
| ID | UserID | CustomerID |
-----------------------------
| 1 | 2 | 3 |
| 2 | 2 | 4 |
| 3 | 2 | 5 |
| 4 | 7 | 6 |
Идентификатор пользователя является идентификатором родительского клиента, а идентификатор пользователя является идентификатором дочернего клиента. Тогда вы могли бы ограничить, кто что видит.
Для вашего вопроса о проектах, то же самое, я бы создал отдельную модель / таблицу под названием ProjectRoles, которая имеет идентификатор проекта, идентификатор пользователя и имя роли. Это прекрасный баланс между обеспечением надежной / долговременной настройки таблицы и быстрой загрузкой запросов. Я бы предпочел, чтобы это было правильно с первого раза!