10

You are building a system that keeps track of Companies. Those companies have Contacts. Those contacts are often specialists that only answer certain types of questions, such as Billing/Payment, Sales, Ordering, and Customer Support.

Using Domain Driven Design and an Onion Architecture, I've modeled this with the following types:

  • Company
    • Has Contacts
  • Contact
    • Has Contact Types
  • ContactType (enum)
  • CompanyRepository (interface)
  • EFCompanyRepository (defined in an external assembly, uses EntityFramework, implements CompanyRepository)

Our team has a split opinion on how to model the database for this application.

Side A: The Lean DDDers:

  • It's the job of the Domain to define which ContactTypes are valid for a Contact. Adding a table to the database to validate that unknown ContactTypes are not saved is a sign of a leaky domain. It spreads logic too far out.
  • Adding a static table to the database and corresponding code is wasteful. In this application the database solves one problem: persist the thing and give it back to me. Writing an extra table and corresponding CRUD code is wasteful.
  • Changing the strategy for persistence should be as easy as possible. It is more likely to change that business rules. If I decide that SQL Server costs too much I don't want to have to rebuild all the validation I put in my schema.

Side B: The Traditionalists [that's probably not a fair name. The DBCentrists?]:

  • It's a bad idea to have data in the database that doesn't make sense without reading code. Reports and other consumers have to repeat the list of values themselves.
  • It's not that much code to load your db type dictionaries on demand. Don't worry about it.
  • If the source of this is code and not data I will have to deploy bits instead of a simple SQL script when it changes.

Neither side is right or wrong, but one of them is probably more efficient in the long run, counting development time for initial development, bugs, etc. Which side is it - or is there a better compromise? What do other teams writing this style of code do?

  • I prefer to have lookup tables in the database and have code (T4 templates in .NET) that generates the enums for me based on the lookup tables in my application code. – programmer Oct 27 '15 at 13:58
  • @JasonHolland Does the T4 template actually perform a query? Otherwise I'm not sure how it generates more than an empty enum with the expected name. – Drew Oct 27 '15 at 14:01
  • 2
    yes it performs a query. Take a look at developerhandbook.com/c-sharp/t4-templates-for-lookup-tables and erraticdev.blogspot.com/2011/01/… – programmer Oct 27 '15 at 14:36
  • For a table with static values,how much CRUD code do you need to write? Script it and be done. – JeffO Oct 27 '15 at 17:05
  • 2
    Traditional CRUD-ist argument about 'well, it won't make sense for reporting' is a non-starter. As soon as you introduce some other responsibility that the system has (to wit, reporting) you have found a business requirement that needs to be handled appropriately. The database is there to store and load the applications own, protected state; allowing it to be reported on creates coupling between your application and the people who need the reports. If DDD is about anything it is about separating these contexts. – Matt Oct 29 '15 at 14:30
4

By adopting DDD and onion architecture, you have decided that database is second to your domain model. That means, there won't be anyone else doing operations on the database other than the model. If traditionalists don't like that, they should have objected to use of DDD in the first place.

First thing is clear : you need the "lookup table" in the model. Your model needs to differentiate between different types of contacts. That means, it keeps strongly-typed list of all types. There also needs to be mapping from those strong types to values that are serialized to database. This mapping can be inside the database module. But the list of all possible types will still be in the model. And if the model is to be single source of truth, then it cannot be inside the database. Or at least, when the list changes in the model, it needs to change in the database. And no buts!

2

Domain objects stop being domain objects when they cross a process boundary. Even if the database is just a persistence store, at some point in the future the demands of the business are going to cause a change to the domaim model that is inconsistent with the persisted history, and you are going to need an anti corruption layer anyway....

That said, I think your DBCentrists are missing the boat. The domain modelers are saying that they need a persistence store. "Reports and other consumers" need something that they can query -- something with decent indexes, as has been noted in comments.

Who introduced the constraint that all of these different concerns needed to be supported by one database? What happens if you push back on that.

Search keyword: CQRS.

1

I have found it best to store enums as their string representation in the database and not include a lookup table.

Obviously the downside to this is that it uses more disk space and is not normalised.

The plus side is that the field retains its meaning in the db, you dont end up with magic numbers corrosponding to the int value of the enum for example and you dont have to manage versioning a lookup table when the enum changes.

Not sure I would characterise this as a DDD vs Trad difference though. Its more a database-centralist vs code is best in my view

  • wondering if databases themselves have such an enum feature these days – herzmeister Oct 27 '15 at 14:42
  • I guess it would depend on the DB, you can do all sorts of crazy CLR stuff with MSSQL. But I am firmly with the 'DB bad, code good' side when it comes to such things – Ewan Oct 27 '15 at 14:46
  • @herzmeister <3 PostgreSQL postgresql.org/docs/9.4/static/datatype-enum.html, Ewan The DB is code once you embrace stored procedures. (PLv8 is wonderful). – Sirisian Oct 28 '15 at 13:10
  • @Sirisian you know that does it blend thing? I have a similar question. "does it scale?" – Ewan Oct 28 '15 at 13:12
  • Do you mean does it do a cross product to turn the enum into a string? Probably not. I'm not sure how it's implemented, but it is faster than using a separate table. It scales. Found this also: stackoverflow.com/questions/2318123/… Still seems like a valid assessment 5 years later. (I tend to write programs highly coupled to PostgreSQL so I use all the features, but not everyone can do that). – Sirisian Oct 28 '15 at 14:08
0
  • As long as you are using a relational database you should keep tables normalized to a reasonable extent. Normalization helps prevent insert and update anomalies.
  • The one-app<->one-database relationship is no longer common, multiple apps can use multiple databases and a single database can be used by multiple apps, so having the database enforce referential integrity as much as possible is good.
  • The RDBMS is your friend.
  • You can go with a key-value storage instead and do everything in code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.