Most of the time, the
ID field you are talking about would be generated by the database, e.g. as a RDBMS sequence or a NoSQL unique identifier. It is therefore tied to the corresponding database backend used.
According to the Persistence Ignorance / Polyglot Persistence principle, you should better hide this
ID from your domain aggregates as much as possible.
In practice, your domain Aggregates may already have an unique identifier. For instance, a serial number, a client code, a logon name, an account number, an invoice reference or an ISBN for a book.
If there is no such "natural" identifier in your model, it may be one role of the domain logic to generate such genuine identifiers, e.g. following a pattern defined by regulation, or human-friendly notions, following your company best practice (it is common to include the year and the month in invoice numbers, or an alphanumeric identifier of the department in charge of the process for instance).
Within the Infrastructure Layer, you would probably let an
ID field appear, especially if you need to construct joined SQL queries among several RBDMS tables. Or, if you use an ORM, you may not persist directly the DDD aggregate objects as ORM objects, but use an "agnostic" translation layer. This is for instance what our DDD framework proposes, by adding an automated translation layer between the DDD plain objects and the ORM objects, which have their own ID... some kind of "square ORM": on DDD mapper over an ORM mapper.
DDD is mainly about isolation: don't pollute your domain with database consideration! Naming an aggregate object field as
ID does definitively smell: there is probably another naming, compatible with the Ubiquitous Language of your bounded context, which may be used instead of a plain