Using Natural key as a DomainObject or GUID + auto-increment Domain Driven Design identifier

I read many articles about DDD and noticed that most of them use the GUID as their identifier when saving the database. The GUID is said to scale well, and automatically increasing the ID is a big no-no when it comes to scalability.

Now I am confused whether to use a GUID or auto-increment .

Basically, the domain is membership system (binary tree). (tracking of register members) membership system (binary tree). (tracking of register members)

The first requirement is that we must have something that uniquely identifies them in the system (we call it Account No. ), possibly 7digit.

The new Members can then be registered with another Member . We call it a referral.

Now what I plan to do is to have a MemberId type GUID as the DomainObject identifier, where it serves as the primary key that will be used for connections, foreign keys (on Referral, referer_id will be the GUID of MemberId ). AccountNo will be a column with automatic promotion or can be obtained from the repository using MAX () + 1. It will be mainly used for search functions in the system and in links.

Should the DomainObject object identifier remain hidden to users of the system since it was just technically implemented?

Is it possible to combine both? GUID as row_id in the database (Surrogate key). and Auto-Increment for (Natural Key)?

Is it possible to exclude AccountNo from the constructor, because it will automatically increase? How about the need to use invariants? So, does the next identifier from the repository get the path and include AccountNo in the constructor?

Should I just use the Auto-Increment ID and forget about the GUID, delete MemberId and let AccountNo be the identifier of the DomainObject?

Note:

I am not creating the next facebook.

I just want to practice the Tactical side of DDD to learn how to make tough architectural decisions, knowing their PROS and CONS.

I just want to practice the strategic side of DDD to learn how to make tough architectural decisions, knowing their PROS and CONS and their implementation.

If we make 3 scenarios with registration of the participant:

  • The first scenario: registration of participants occurs every minute.
  • Second scenario: registration of participants occurs every hour.
  • Scenario Three: Registration of participants takes a maximum of 5 days.

How will this affect decisions?

Technological stack:

  • ASP MVC 5
  • Sql Server 2014
  • FROM#
  • Dapper ORM
+4
source share
4 answers

I just want to practice the Tactical side of DDD to learn how to make tough architectural decisions, knowing their PROS and CONS.

You are wrong. You cannot learn strategy by doing tactics. Tactics are ways to implement strategy. But first you need a strategy.

Anyway, about your question, it's pretty simple: use Guid. It has 2 advantages

  • global identifier
  • can be easily generated from the application. Automatically increasing identifier means complex service or db dependency. Do not complicate your life.

A natural identifier such as AccountNo should also be used. However, guidance exists for technical purposes. The format of natural keys may change in the future. The manual makes it easy to support natural key multiple formats.

As a practice, it’s best to have your object identifier be a value object (even if it's just a Guid). You can include guid in AccountNo too, VO does not have to be just one value. For example, in my current application, I have ProjectId(Guid organization,Guid idValue) and ProjectAssetId(Guid organization,Guid projectId,Guid idValue) .

+3
source

There are probably too many questions in your question to give you a complete answer, because the design of the ID is not simple and has many aspects. I can recommend the book "Implementation of DDD" by Vaughn Vernon, it has a section on identity design (Chapter 5, "Entities" - Unique Identification).

In any case, I'm trying to point you in the right direction without repeating everything from this chapter :-).

What you need?

You have already pointed out some questions regarding ID design, but there are still questions you need to ask. Only then can you decide if the GUIDs, DBs are suitable or still different.

  • What is the domain value for the identifier? The identifier is probably there to facilitate the technical solution, but is it not part of the domain at all?
  • Who provides the identifier? This can be a user, application, database, or another limited context.
  • When do you need an identifier? Before creating a linked object during creation or only when saving an object?

Answers to these questions will limit the type of identifier generation you can use.

What you need to know about

There are several rules regarding ID design. After them, it is highly recommended that you do not shoot in the leg later:

  • Make sure your identifiers are unique. This may especially be due to identifiers provided by the user. You must ensure uniqueness and enable your users to discover existing identifiers. With arbitrary identifiers or identifiers generated by the database, this is usually not a problem.
  • Make sure your identifiers are stable. Never change the identifier of an object! After all, an identifier is what you use to refer to an object. The consequence of this is that you should not make things part of your identifier, which may change. For instance. A person’s last name cannot be a good choice, because it can change when someone marries (and it can be problematic due to non-uniqueness too).
  • Hide identifiers if they are just a technical concept. Drawing up a technical concept as part of your domain model is wrong in terms of DDD.

Example

Here is an example of how you can find the design ID:

Allowing lateness to be created (e.g. persistence) means that you have an object without an identifier when you simply create the object. Therefore, if you need early or temporary identifiers, you cannot use identifiers created using the database (if you do not agree to contact the database only to obtain the ID).

Then you can decide that the user is not interested in the ID, so specifying the ID will be strange. This leaves the identifiers created by the application.

With the identifiers generated by the application, you need to make sure that the identifier is unique. This is trivial for single-instance applications, but can be more problematic once you create a load-balanced setup with more than one application instance. This is the reason many people use random identifiers (like GUIDs) in the first place, so they don’t get stuck when scaling.

As you can see, this example makes a lot of assumptions. It is simply wrong or wrong there, but with the above questions you must make an informed decision.

+2
source

Let me defend the idea of ​​auto zoom. It is true that GUIDs are more scalable. But the important question that any designer should ask at some point is, "What scalability do I need?"

The answer is very rare, "As much as possible!" In the real world, everything has its limits. Our databases simulate the real world.

For example, if you work with people (users, customers, students, etc.), a 64-bit integer can repeatedly contain the entire population of the Earth. So many times. Here we are talking about the "population of the galactic empire." Using bigint, you can uniquely identify each atom in the universe.

Do not be lazy, especially at the design stage. Create a reasonable margin of safety and continue. Anything that more unjustifiably increases the complexity and "friction" of the system.

My experience in this area is now measured for decades - several of them. At that time, I never had to use a GUID for scalability. The only actual use of the GUID that I found is when entities are created in different, usually remote, databases, which then need to be combined into a central database. GUIDs eliminate (statistically speaking, that is) the possibility of collisions during a merge.

+1
source

The GUID is said to scale well, and automatically increasing IDs is a great no-no value when it comes to scalability.

The main scalability problem with auto-incrementing integers is related to inserts: since new values ​​are “grouped” together at the top of the value range, they tend to fall on the same “side” of the B-tree (and probably the same leaf node), causing concurrency to commit and lower.

Only once a minute you simply won’t see anything like this, so choose your key based on other criteria. As you described, auto-added integers in your script will be very convenient ... they are lighter and will most likely work better than the GUID. And if the 32-bit version is not wide enough, just use the 64-bit version.


BTW, integers with auto-increment are not generated by a query for MAX() + 1 - all DBMSs have their own version of a high-performance sequence generator, which you can use directly.

You can also return the generated value directly to the client, without requiring an additional round (for example, Oracle RETURNING or SQL Server OUTPUT). Unfortunately, ORMs do not always go well with this ...

0
source

All Articles