6

I've been reading up a lot on Domain-Driven Development, and I came to the question of how to preserve lack of distinct identity with value objects (VOs). While in the DDD world, this is a requirement (yet I'm not sure I understand the full power of this) it poses problems for the lower ORM layers in terms of persistence.

Tables, for the most part, like to be normalized. It makes life easy in terms of having no delete or insertion anomalies. My concern comes when implementing VOs; they do have primary keys - identities by definition (and foreign keys to their parent). Making them entities is violating DDD in favor of persistence. Instead, I could make a wrapper class that accepts a "bag" of parameters, and then attaches them to each parent's foreign key. While mechanically messy, it sounds like it will work.

I've read a lot of responses on the internet (Stack Overflow also) about denormalizing tables. This concerns me, as now we're violating persistence for DDD.

How to allow VOs to exist by their proper definition without a denormalization?

gnat
  • 21,442
  • 29
  • 112
  • 288
AdrianGW
  • 71
  • 1
  • 3
  • If you're talking in abstract terms, then fair enough but if this is happening on an existing system, it sounds like it could be a code smell. Value objects either tend to be normalized or exist in metadata tables. – Robbie Dee Feb 05 '14 at 10:39
  • The denormalization being the smell? – AdrianGW Feb 05 '14 at 10:41
  • I mean a contrived key could be a code smell. Consider phone numbers. These can be presented in the customer table in a denormalized way (e.g. home phone, work phone and mobile phone columns) or put into a separate table with customer number and phone number as the key or separated out with an additional type (H, W, M). Which method you use determines if you're talking about a value type or entity. You might just be interested in customer phone numbers in which case, you don't need a key (VO), or you may want to find the work phone in which case the key is customer number and type (entity). – Robbie Dee Feb 05 '14 at 11:03
  • H, W, M would be defined in a metadata table so the linkage would be **customer-->customer_phone_number-->phone_number_type** – Robbie Dee Feb 05 '14 at 11:08
  • Right, but I'm concerned by the speed at which tables appear to be denormalized. While it can definitely yield advantages, such as for warehousing, etc. the benefits of being able to index by each independent field, etc. are huge. For example, getting all users with the same phone number will be difficult if embedded in some encoding inside a field (bizarre example, but you get the point). I don't know the scope of the domain well enough to state that I'm comfortable with that sacrifice. – AdrianGW Feb 05 '14 at 11:14
  • The traditional (database first) approach has been to design the logical DB first and then denormalize into the physical DB with representative volumes and queries. In the code first approach, how you use the data drives the database design. In either case, you want your representative queries to perform. – Robbie Dee Feb 05 '14 at 11:29
  • Right, that makes sense. It's a different approach with a different domain of requirements. Cleaner, business level domain over metadata and programmatic wiring. – AdrianGW Feb 05 '14 at 11:33
  • You should keep in mind that even if you're using a RDBMS some bits of the model (Domain objects) are easier to store in a key-value table at least the 'command' model. Basically you should aim to come up with the best persistence strategy for different parts of the model instead of one way of doing things. A kv store will alow to store ANY domain object state in serialized form, regardless of the object structure. It's very maintainable but it applies mainly (99%) to the Command model. The Read model can be stored in the 'traditional' relational way, it depends on your query needs. – MikeSW Feb 05 '14 at 12:26

4 Answers4

5

I really don't think there is problem of VOs having an identity in database, as long as this identity remains hidden and transparent in domain layer itself. I would be data layer's responsibility to keep track of those identities so the domain doesn't have to care about it.

But VOs still give you ability to denormalize. Denormalization can have it's advantages, usually for performance reasons. So you can use this to your advantage.

Euphoric
  • 36,735
  • 6
  • 78
  • 110
  • "...as long as this identity remains hidden and transparent in domain layer itself" Bingo. That's the only way I'd allow them to have some primary key, enforcing the notion of DDD. The problem is, now can this be done? Let's say there is some ORM layer, mapping a one-to-one, isomorphic structure between the database and an object. Do I need another layer "on top" that masks the id field and emulates immutability? – AdrianGW Feb 05 '14 at 10:43
  • "ORM layer, mapping a one-to-one" Thats where you are wrong. The ORM layer can add new properties into the model and as long as the layers are properly designed, this shouldn't pose a problem. But I agree this is extremely hard to do right. Especially when ORM doesn't help this. – Euphoric Feb 05 '14 at 10:45
  • Right, so this would bring the ORM directly as the "domain layer", by adding "new properties into the model", correct? If this were the case, preventing access from the primary key of value objects becomes difficult. It feels like DDD is too close to persistence. – AdrianGW Feb 05 '14 at 10:48
  • "ORM directly as the "domain layer", by adding "new properties into the model", correct?" No. It should be possible to extend the model so it can be properly persisted, but this extension should be in the persistence. You could extend the classes and add appropriate properties, but this extension should be irrelevant to domain layer itself. This is already done by ORM to facilitate POCO persistence. – Euphoric Feb 05 '14 at 11:14
  • Yes, that's right. Put differently, if the ORM is exposing the primary keys, where does this "identity based object" turn into a value object? Where does the primary key become inaccessible? – AdrianGW Feb 05 '14 at 11:22
  • I don't think "where?" is good question. It is not that the key "becomes inaccessible". The key never exists in the domain and is just accessible by the persistence layer, because it was added by this layer. It is really hard to explain without going into details about design of the whole architecture of this. – Euphoric Feb 05 '14 at 11:27
  • Instead of clogging up this public space, is there some way I can contact you @Euphoric? – AdrianGW Feb 05 '14 at 11:31
  • @AdrianGW Sorry, I don't really have time for this kind of discussion. – Euphoric Feb 05 '14 at 11:34
  • @AdrianGW If you come across a real life example, that might grease the wheels a little. Trying to figure out abstract implementation details can be a little difficult. – Robbie Dee Feb 06 '14 at 08:55
  • If you end up with an identity, even if its just in the db, doesn't that suggest that the VO is in fact an entity? I'm having a hard time coming up with a VO that would have its own PK in the DB but not in the domain. VOs in DDD seem to strongly correlate with Value Types in .Net, for example. – Andy Feb 23 '15 at 13:40
2

This is an issue if you use an ORM to map your domain objects directly to the DB. This falls apart rather quickly for all but the most trivial of applications. Instead create separate classes to represent your data store and map those. You will need code that maps the BOs to the DTOs, but you will not be forced to compromise your domain classes to make the ORM happy, which is invariably what happens. You will also avoid the leaky abstraction that comes with using a ORM.

Given the above, how you persist value objects depends. If you're storing for example geo coordinates, I probably wouldn't normalize these and store them in the same table as the entity. If your value types really do have their own identity though, that suggests to me that they probably shouldn't be value objects in your domain layer. That's really the defining difference between a value object and entity in DDD. I always like to go to the source for DDD; unfortunately many of the blogs you'll see on the internet (especially those that really like NHibernate) don't really get DDD right at all, and following their advise usually leads you to the anemic domain model anti-pattern.

Andy
  • 2,003
  • 16
  • 22
  • Thanks for this comment! Indeed, this is what I've found; the ORM models themselves need to be wrapped up rather quickly, and these are usually just another abstraction on top of the persistence. The real DDD kicks in immediately above. Thanks for this! :) – AdrianGW Feb 23 '15 at 03:11
  • @AdrianGW Hmm, I suppose I didn't properly answer your question. I'll fix my answer. – Andy Feb 23 '15 at 13:26
  • @AdrianGW I've expanded my answer; hopefully this is more useful now. – Andy Feb 23 '15 at 13:38
  • Thanks for this! Any way I can contact you? I'd like to thank you for the advice and ask you a few questions :) – AdrianGW Feb 25 '15 at 00:41
0

Database identity and domain identity are not same things, on db level you are allowed to do whatever optimization you need and in domain layer you decide (business requirements) how would you handle your models - as entities or value objects.

In relational db's I like to put unique constraint on fields that compose my value object just to be sure to keep value object safe, if there are some foreign keys - all fine.

sMs
  • 301
  • 2
  • 4
0

The main property of Value Objects (i.e. values) beside that they are immutable is that they are exchangeable.

So if I set a value to "3", it doesn't make any difference at all to set it to a "different" "3". 3 is just 3, it's a value.

It doesn't really make any difference how you persist it, the important part is that these properties hold. The question is: do they? If your value has a reference to its "parent", or even an Id, can I really exchange that value to another equal value? I guess it might be possible, but it seems sketchy.

Robert Bräutigam
  • 11,473
  • 1
  • 17
  • 36