Hi Per,
[my previous mail was sent out accidentally before I finished typing it]
using ID's expressed in the Ubiquitous Language is something I would really recommend. In Axon, I have chosen to use the UUID for several reasons. Before I explain what these are, I would like to say that the fact that UUID is final should not withhold you from using it.
In general, it is considered good practice to favor composition over inheritance. That means your OrderId would look as follows:
public class OrderId {
private final UUID identifier; // note that this could also be a String value, which is more Hibernate compatible
public static OrderId fromUUID(UUID identifier) {
return new OrderId(identifier);
}
private OrderId(UUID identifier) {
this.identifier = identifier
}
public UUID toUUID() {
return identifier;
}
@Override
public String toString() {
return identifier.toString();
}
}
In your commands, you would use OrderId to explicitly distinguish between ID's of different types of aggregates. When loading from a repository, you could do:
repository.load(orderId.toUUID(), expectedVersion) // or without the second parameter, if you're on Axon 0.5
Another nice approach would be to also add the version attribute, and make it a versioned identifier. This returned identifier would normally be given to a UI through a query. This UI doesn't have
to bother with versions, all it has to do is pass the versioned ID it got from the query back into the command, and concurrent modification are automatically detected. (Note: concurrent modification detection is available since 0.6)
Note that an aggregate may always be generated with an existing identifier. There is nothing against using "super(identifier)" in the constructor of an aggregate. Just make sure that there is a clear difference between the constructor in your implementation used to reconstruct an existing aggreggate, and the one for creating a new one altogether.
I hope this helps you on your way.
As promised, here are some reasons for choosing UUID as primary identifier of aggregates and events:
- UUID is a global standard for unique identifiers
- UUID's support scalability. Sequence numbers withold scalabilty, since machines need to communicate with eachother to prevent them from generating the same ID's.
- UUID's have different formats, you can convert almost any type of identifier into a UUID. For example, if you use a sequence number for invoice ID's (which is a legal obligation in many countries),
you could generate that as a long, and use a version 5 UUID, which uses SHA-1 to compute a UUID for any input.
And one could think of more reasons, of course.
Cheers,
Allard