Использование Natural key в качестве идентификатора DomainObject или GUID + автоинкрементный дизайн, управляемый доменом
Я читал много статей о DDD и заметил, что большинство используют GUID в качестве идентификатора при сохранении в базе данных. Говорят, что GUID хорошо масштабируется, а идентификаторы с автоматическим инкрементом увеличиваются, когда речь идет о масштабируемости.
Я в замешательстве теперь, чтобы использовать GUID
или же auto-increment
,
В основном Домен о membership system (binary tree). (tracking of register members)
Первое требование состоит в том, что у нас должно быть что-то, что однозначно идентифицирует их в системе (мы называем это Account No.
) возможно 7 цифр.
Тогда новый Members
может быть зарегистрирован другим Member
, Мы называем это рефералом.
Теперь то, что я планирую сделать, это иметь MemberId
типа GUID в качестве идентификатора DomainObject Id, где он служит первичным ключом, который будет использоваться для соединений, внешних ключей (по ссылке, referer_id будет GUID MemberId
). AccountNo
будет столбцом с автоинкрементом или, возможно, он будет получен из репозитория с помощью MAX() + 1. В основном он будет использоваться для функций поиска в системе и в ссылках.
Должен ли идентификатор DomainObject оставаться скрытым для пользователей системы, поскольку это всего лишь техническая реализация?
Можно ли комбинировать оба? GUID как row_id в базе данных (суррогатный ключ). и автоинкремент для (натуральный ключ)?
Можно ли исключить AccountNo
из конструктора, потому что он все равно будет автоматически увеличен? Как насчет необходимости применять инварианты? Итак, как получить следующий идентификатор из репозитория? AccountNo
в конструкторе?
Должен ли я просто использовать Auto-Increment ID и забыть о GUID, удалите MemberId
и пусть AccountNo
быть идентификатором DomainObject?
НОТА:
Я не создаю следующий Facebook какой-то.
Я просто хочу попрактиковаться в тактической стороне DDD, чтобы научиться принимать сложные архитектурные решения, зная их плюсы и минусы.
Я просто хочу попрактиковаться в стратегической стороне DDD, чтобы узнать, как принимать сложные архитектурные решения, зная их плюсы и минусы и их реализацию.
Если мы сделаем 3 сценария с регистрацией участника:
- Первый сценарий: регистрация участника происходит каждую минуту.
- Второй сценарий: регистрация участника происходит каждый час.
- Третий сценарий: регистрация участника происходит максимум 5 раз в день.
Как это повлияет на решения?
Технологический стек:
- ASP MVC 5
- SQL Server 2014
- C#
- Dapper ORM
4 ответа
Я просто хочу попрактиковаться в тактической стороне DDD, чтобы научиться принимать сложные архитектурные решения, зная их плюсы и минусы.
Вы ошиблись. Вы не можете изучить стратегию, выполняя тактику. Тактика - это способ реализации стратегии. Но сначала вам нужна стратегия.
В любом случае, по вашему вопросу все довольно просто: используйте Guid. Имеет 2 преимущества
- глобальный идентификатор
- могут быть легко созданы из приложения. Автоматически увеличенный идентификатор означает сложную услугу или зависимость от БД. Не усложняй свою жизнь.
Естественный идентификатор, такой как AccountNo, также должен использоваться. Тем не менее, Guid там для технических целей. Формат естественных ключей может измениться в будущем, Guid облегчает поддержку нескольких форматов естественных ключей.
На практике лучше всего, чтобы ваша сущность идентифицировалась как объект значения (даже если это просто Guid). Вы можете включить гид в AccountNo
Кроме того, VO не должно быть только одно значение. Например, в моем текущем приложении у меня есть ProjectId(Guid organization,Guid idValue)
а также ProjectAssetId(Guid organization,Guid projectId,Guid idValue)
,
Вероятно, в вашем вопросе слишком много вопросов, чтобы дать вам полный ответ, потому что дизайн ID не прост и имеет много аспектов. Я могу порекомендовать книгу Вон Вернона "Внедрение DDD", в ней есть раздел, посвященный дизайну идентичности (глава 5 "Сущности" - уникальная идентичность).
В любом случае я стараюсь направить вас в правильном направлении, не читая ничего из этой главы:-) .
Что вам нужно?
Вы уже задали некоторые вопросы относительно дизайна удостоверения личности, но есть еще вопросы, которые вам нужно задать. Только тогда вы сможете решить, подходят ли GUID, сгенерированные БД или все еще другие идентификаторы.
- Что такое доменное значение идентификатора? Вероятно, идентификатор используется только для облегчения технического решения, но не является частью домена вообще?
- Кто предоставляет удостоверение личности? Это может быть пользователь, приложение, база данных или даже другой ограниченный контекст.
- Когда вам нужно удостоверение личности? До создания связанного объекта, во время создания или только когда объект сохраняется?
Ответы на эти вопросы будут ограничивать тип генерации идентификатора, который вы можете использовать.
Что вы должны знать
Есть несколько правил, касающихся дизайна ID. Настоятельно рекомендуется следовать им, чтобы потом не выстрелить себе в ногу:
- Убедитесь, что ваши идентификаторы уникальны. Это может особенно касаться предоставленных пользователем идентификаторов. Вам необходимо обеспечить уникальность и дать своим пользователям возможность обнаруживать существующие идентификаторы. С генерируемыми приложением случайными идентификаторами или сгенерированными БД идентификаторами это обычно не проблема.
- Убедитесь, что ваши идентификаторы стабильны. Никогда не меняйте ID объекта! В конце концов, идентификатор - это то, что вы используете для ссылки на сущность. Следствием этого является то, что вы не должны включать в свой документ такие вещи, которые могут измениться. Например, фамилия человека не может быть хорошим выбором, потому что это может измениться, когда кто-то выходит замуж (и это может быть проблематично из-за неуникальности тоже).
- Скрыть идентификаторы, если они просто техническая концепция. Делать техническую концепцию частью вашей доменной модели неправильно с точки зрения DDD.
пример
Вот пример того, как вы можете найти дизайн ID:
Разрешение на создание идентификатора с опозданием (т. Е. Постоянством) означает, что у вас есть объект без идентификатора, когда вы просто создаете объект. Поэтому, если вам нужны ранние или своевременные идентификаторы, вы не можете использовать сгенерированные БД идентификаторы (если только вы не согласитесь связаться с БД только для получения идентификатора).
Затем вы можете решить, что пользователь не интересуется идентификатором, поэтому указание идентификатора будет странным. Это оставляет сгенерированные приложением идентификаторы.
С идентификаторами, сгенерированными приложением, вы должны убедиться, что идентификатор уникален. Это тривиально для приложений с одним экземпляром, но может оказаться более проблематичным, как только вы создадите установку с балансировкой нагрузки для нескольких экземпляров приложения. Это причина, почему многие люди используют случайные идентификаторы (например, GUID), поэтому они не попадают в тупик при масштабировании.
Как видите, этот пример делает много предположений. Там просто нет правильного или неправильного, но с вопросами, изложенными выше, вы сможете принять обоснованное решение.
Позвольте мне защитить идею автоинкремента. Это правда, что GUID являются более масштабируемыми. Но важный вопрос, который любой дизайнер должен задать в какой-то момент: "Сколько масштабируемости мне нужно?"
Ответ очень редко "Как можно больше!" В реальном мире все имеет пределы. Наши базы данных моделируют реальный мир.
Например, если вы работаете с людьми (пользователями, клиентами, студентами и т. Д.), 64-разрядное целое число может многократно содержать все население Земли. Очень много раз. Мы говорим о "населении галактической империи" здесь. Используя bigint, вы можете однозначно идентифицировать каждый атом во вселенной.
Не ленитесь, особенно на этапе проектирования. Разработайте разумный запас прочности и продолжайте. Все, что более излишне, увеличивает сложность и "трение" системы.
Мой опыт в этой области сейчас измеряется десятилетиями - несколько из них. В то время мне никогда не приходилось использовать GUID для масштабируемости. Единственное фактическое использование GUID, которое я обнаружил, - это когда объекты создаются в разных, обычно удаленных, базах данных, которые затем должны объединяться в центральную базу данных. Идентификаторы GUID исключают (то есть, статистически) вероятность столкновения при слиянии.
Говорят, что GUID хорошо масштабируется, а идентификаторы с автоматическим инкрементом увеличиваются, когда речь идет о масштабируемости.
Основная проблема с масштабируемостью для целых чисел с автоинкрементом заключается во вставках: поскольку новые значения "собираются" вместе в верхнем экстремуме диапазона значений, они имеют тенденцию попадать на одну и ту же "сторону" B-дерева (и, вероятно, одинаковы листовой узел), вызывая фиксацию и понижение параллелизма.
При вставке раз в минуту вы просто не увидите ничего подобного, поэтому выбирайте ключ по другим критериям. Как вы уже описали, целые числа с автоинкрементом вполне подойдут в вашем сценарии... они более легкие и, вероятно, будут работать лучше, чем GUID. И если 32-битный вариант недостаточно широк, просто используйте 64-битный.
Кстати, автоинкрементные целые числа не генерируются путем запроса MAX() + 1
- все СУБД имеют собственную версию высокопроизводительного "генератора последовательностей", которую вы можете использовать напрямую.
Вы также можете вернуть сгенерированное значение непосредственно клиенту, не требуя дополнительного обхода (например, предложение Oracle RETURNING или SQL Server OUTPUT). К сожалению, ORM не всегда хорошо играют с этим...